为什么在枢轴项中Frame属性为null?

时间:2014-11-23 16:44:47

标签: c# windows-phone windows-phone-8.1

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

<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属性?作为后续内容:我应该如何从枢轴项目导航?

2 个答案:

答案 0 :(得分:3)

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

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

以这种方式获取Frame非常常见且安全。除{em>你将其放在那里之外,Frame中的Window.Current.Content除了Frame之外什么都不会。在这种情况下,根本不会成为Window.Current.Content,你无论如何都无法像这样导航(也就是说,你必须手动更改{{1}显示其他内容的属性,并手动管理后退按钮。)

一些想法/建议

我建议您使用静态Navigate方法创建一个静态类,它可以完成工作(获取Frame并调用其Navigate方法)。

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

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

您应该使用UserControl而不是Page

Page是要在整个屏幕上显示的应用的一部分。它不是另一页的一部分。你使用它的方式,就像UserControl一样(在这种情况下你应该使用它)。 Page特定功能仅在您使用Frame对象导航到该功能时才有效。

另一方面,

用户控件和模板化控件是页面的可重用部分。因此,如果您需要在多个页面中拥有一些UI(及其功能),您可以制作其中一个控件。

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

硬件返回按钮

你似乎不再需要这个了,但我还是会说几行。

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

修改

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

答案 1 :(得分:1)

我不确定这是不是最好的答案(我确定不是:)但应该有效。

问题是CampsPage是我怀疑 Page 类在 Frame 之外的其他容器中。您尚未导航到该页面,它不在Window.Current.Content内 - 它位于 Pivot 中。因此, Frame 属性为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

<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));

就像我说的那样,可能有更好的解决方案,但除非没有别的,否则这可能会有用。

can download from GitHub的一个例子。