...">

Why is the Frame property null on a pivot item?

I have a summary page defined like this:

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

      

Let's take the first page ( CampsPage

) as an example : it contains ListBox

an overview of the camps. when the item is clicked, it should go to the detail view. To navigate, I thought this should be enough:

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

      

but this calls a NullReferenceException

, because Frame

apparently null

.

On the other hand, it does navigation like this:

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

      

And this approach:

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

      

Why is the property Frame

not set in the pivot position? And as a follow up: how do I navigate out of the pivots?

+3


source to share


2 answers


You seem to have already found most of the information you need. I can confirm that this is the way to navigate (as you yourself suggested):

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

      

Obtaining Frame

in this way is fairly common and safe. There Window.Current.Content

will be nothing in it except Frame

if you have not placed it. In this case, it simply won't Frame

, and you still won't be able to navigate that way (ie, you have to manually change the property Window.Current.Content

to show different content, and manually manipulate the Back button).

Some ideas / suggestions

I would suggest creating a static class with a static method Navigate

that does the job (gets the Frame and calls its method Navigate

).

It might be even more convenient to (also) make an extension method for the UserControl class that does navigation. This way you just call this.Navigate(typeof(CampDetail), selectedCamp)

on all UserControls.

I also suggest being consistent and always using this method and never using the property Page.Frame

(unless you really need to, for some reason). This will make it easier to find / troubleshoot navigation related problems as every navigation will go through this method.

You have to use UserControl instead of Page



A Page

is part of the application that should be displayed in full screen. It is not considered part of another page. The way you use it, it works like a UserControl (which is what you should be using in this case). Page

-specific functions will only work if you navigate to it using an object Frame

.

Custom controls and templated controls, on the other hand, are reusable parts of pages. So, if you need to have some user interface (with its functionality) on multiple pages - you make one of these controls.

So, I suggest you change <views:CampsPage/>

, <views:CalendarPage/>

and <views:LoginPage/>

to UserControls instead of Pages. If you need pages (for navigation purposes), create pages that simply display these UserControls.

Back button

You don't seem to need this anymore, but I'll put a few lines in anyway.

Default "Back" button simply indicates Frame

in Window.Current.Content

on GoBack()

, if possible
close the application. You can manually handle the Back button and perform some non-default actions using an event HardwareButtons.BackPressed

.

Edit

I was wrong about the default button action and fixed it. I'm pretty sure it automatically moved back through the stack.

+2


source


I'm not sure if this is the best answer (I'm sure it isn't :), but it should work.

The problem is what CampsPage

is, as I suspect, the class of the page inside a different container than the Frame. You didn't go to this page, it's not inside Window.Current.Content

- inside Pivot. Thus, the Frame property has a value null

.

Here's my ugly approach:

Extend your page class with DependencyProperty - links to the parent 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));
}

      

Then make your CampsPage

(and another) this ExtendedPage type. Then bind the ParentPage property to the current page inside the frame:



<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

      

Then you can navigate CampsPage

like this:

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

      

As I said, there are probably beter solutions, but if not otherwise, it might be helpful.

Example: can be downloaded from GitHub .

+1


source







All Articles