为什么 Frame 属性在透视项中为空

本文关键字:透视 Frame 属性 为什么 | 更新日期: 2023-09-27 18:31:32

我有一个像这样定义的透视页面:

<Grid x:Name="LayoutRoot" Background="Transparent" >
    <Pivot Title="JOETZ">
        <PivotItem Header="kampen" Name="PvOne">
            <views:CampsPage/>
        </PivotItem>
        <PivotItem Header="kalender" Name="PvTwo">
            <views:CalendarPage/>
        </PivotItem>
        <PivotItem Header="profiel" Name="PvThree">
            <views:LoginPage/>
        </PivotItem>
    </Pivot>
</Grid>

以第一页(CampsPage)为例:它包含一个ListBox,概述了营地。 单击某个项目时,它应转到详细信息视图。为了导航,我认为这应该足够了:

Frame.Navigate(typeof(CampDetail), selectedCamp);

但这引起了NullReferenceException,因为Frame显然是null.

另一方面,像这样进行导航是有效的:

var frame = Window.Current.Content as Frame;
if (frame == null) { return; }
frame.Navigate(typeof(CampDetail), selectedCamp);

这种方法也是如此:

var frame = ((App) Application.Current).RootFrame;
frame.Navigate(typeof(CampDetail), selectedCamp);

为什么不在透视项中设置 Frame 属性?作为后续行动:我应该如何从透视项导航?

为什么 Frame 属性在透视项中为空

您似乎已经找到了所需的大部分信息。我可以确认这是导航方式(正如您自己建议的那样):

var frame = (Frame)Window.Current.Content;
frame.Navigate(typeof(CampDetail), selectedCamp);

以这种方式获得Frame是非常普遍和安全的。除非把它放在那里,否则Window.Current.Content里除了Frame之外不会有任何东西。在这种情况下,根本不会有Frame,并且无论如何您都无法像这样导航(也就是说,您必须手动更改 Window.Current.Content 属性以显示其他内容,并手动管理后退按钮)。

一些想法/建议

我建议你创建一个带有静态Navigate方法的静态类,该方法可以完成工作(获取 Frame 并调用其 Navigate 方法)。

也许更方便的是(也)为执行导航的 UserControl 类创建一个扩展方法。这样,您只需在所有用户控件中调用this.Navigate(typeof(CampDetail), selectedCamp)

我还建议保持一致并始终使用此方法,并且永远不要使用 Page.Frame 属性(除非您出于某种原因确实需要)。这将使查找/解决与导航相关的问题变得更加容易,因为每个导航都将通过该方法。

您应该使用用户控件而不是页面

Page是要在整个屏幕上显示的应用程序的一部分。它不被排除为另一个页面的一部分。你使用它的方式,它的工作方式类似于用户控件(在这种情况下你应该使用)。特定于 Page 的功能只有在使用 Frame 对象导航到它时才有效。

另一方面,用户控件和模板化控件是页面的可重用部分。因此,如果您需要在多个页面中具有一些 UI(及其功能),则可以创建这些控件之一。

因此,我建议您将<views:CampsPage/><views:CalendarPage/><views:LoginPage/>更改为UserControls而不是Pages。如果还需要页面(用于导航目的),请制作仅显示这些用户控件的页面。

"硬件后退"按钮

你似乎不再需要这个了,但无论如何我都会放几行。

默认情况下,"后退"按钮仅告诉Window.Current.Content中的Frame GoBack()如果可能,则会关闭应用程序。您可以手动处理后退按钮,并使用 HardwareButtons.BackPressed 事件执行一些非默认操作。

编辑

我对后退按钮的默认操作是错误的并修复了它。我很确定它曾经自动导航回堆栈。

我不确定这是否是最佳答案(我确定它不是:)但应该工作。

问题是CampsPage是我怀疑 Page 类在 Frame 以外的其他容器中。您尚未导航到该页面,它不在Window.Current.Content内部 - 它在 Pivot 内部。因此,它的框架属性是null

这是我的丑陋方法:

使用 DependencyProperty 扩展 Page 类 - 对父页面的引用:

public class ExtendedPage : Page
{
    public Page ParentPage
    {
        get { return (Page)GetValue(ParentPageProperty); }
        set { SetValue(ParentPageProperty, value); }
    }
    public static readonly DependencyProperty ParentPageProperty =
        DependencyProperty.Register("ParentPage", typeof(Page), typeof(Page), new PropertyMetadata(0));
}

然后,将您的CampsPage(和其他)设置为此扩展页面类型。然后将 ParentPage 属性绑定到框架内的当前页面

<Page Name="MyMainPage" ... rest of things ...>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Pivot Title="JOETZ">
            <PivotItem Header="kampen" Name="PvOne">
                <local:CampsPage ParentPage="{Binding ElementName=MyMainPage}"/>
            </PivotItem>
... rest of the code

然后,您可以像这样在CampsPage中导航:

ParentPage.Frame.Navigate(typeof(DetailPage));

就像我说过的,可能有赌注解决方案,但除非没有其他解决方案,否则也许这会很有用。

您可以从 GitHub 下载的示例。