Managing the Back Stack

Mango From Scratch

In a previous posting, I discussed creating Reminders.  One little known feature of ImageCrop reminders is that you can click on the Reminder to return to the original application (the application in which you set the Reminder).  For example, if I set a reminder to write in my blog, when that reminder comes up, I can click on it and return to the application from which I set that reminder; perhaps to set another reminder or to find additional details.

This raises an interesting problem, however.  When I return to the application, as far as Windows Phone is concerned, I’m at the first page. Clicking the back button from here will exit the application, which is almost certainly not what I want.

To see the problem and its solution clearly, let’s create a new application. 

This posting is based on Peter Torr’s excellent presentation at Mix

On MainPage.xaml we’ll set the application name to Deep Navigation and the page name to Tasks.  This page will  consist of three buttons (though we’ll only wire up the first two):

  1. Blog
  2. Video
  3. Presentations

Let’s tackle Blog first.  The idea is that you can click on Blog, see what work you have to do and then optionally click on Reminder to be reminded to do that work.  After creating the three buttons, double-click on the Blog button to create an event handler. 

private void Blog_Click( 
    object sender, RoutedEventArgs e )
{
    NavigationService.Navigate( 
        new Uri("/Blogs.xaml", UriKind.Relative ));

}

 

In the Blog page we’ll have data relating to the work I need to do for the Blog and a Reminder button. 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
    <TextBlock TextWrapping="Wrap"
        Text="Lorem ipsum dolor sit amet, consectetur 
               Vivamus hendrerit odio a nisi condimentum 
               dignissim. Morbi quis lectus non lectus  
               Morbi facilisis urna sed purus consequat
               rutrum. Fusce ut urna neque, quis sagittis
               taciti sociosqu ad litora torquent per 
               inceptos himenaeos. Mauris luctus velit 
               convallis aliquet. Morbi id massa odio, 
               Duis turpis magna, faucibus ut laoreet , 
               dapibus vitae erat. Nunc feugiat varius 
               facilisis. Pellentesque eu sapien mauris.
               felis laoreet cursus." />

        <StackPanel
            Orientation="Horizontal">
            <Button
        Name="BlogReminder"
        Content="Reminder"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
                Click="BlogReminder_Click" />
        </StackPanel>
    </StackPanel>
</Grid>

 

Note that the BlogReminder button  has a click event handler; this code is in the code-behind and is identical to the way we set up a reminder in the previous article,

private void BlogReminder_Click( 
    object sender, RoutedEventArgs e )
{
    Reminder r = new Reminder( "BlogTask" );
    r.Title = "Blog Reminder";
    r.Content = "Write Blog entry on navigation";
    r.BeginTime = DateTime.Now.AddSeconds( 15 );
    r.NavigationUri = NavigationService.CurrentSource;

    ScheduledActionService.Add( r );  
}

 

Run the application.  When it opens, you’ll see the Tasks page with the three buttons.  Click on Blog and you see the Blog page.  Click Reminder.  Next, click the back arrow twice to exit the application.  Wait about 15 seconds and the reminder will appear.  

Rather than clicking on Dismiss, click the text for the application itselfImageCropClose (and see the built-in tilt effect!).  This will  cause you to return to the Blog page.  Perfect.  Except, how do you get back to the list of Tasks?

As far as Windows Phone is concerned, the Blog page is now the first page. Clicking the back key from here will exit the application. Not what I want. 

The Solution 

To see how to solve this problem, create another page, Video that is identical to the Blog page (except substituting Video for Blog) and wire it to the second button.  Make one more change to the new Video page; add a second button (in addition to Reminder) that says “Tasks”.  Put the two buttons into a StackPanel so they appear side by side, but set the new button’s Visibility to Collapsed

<StackPanel
    Orientation="Horizontal">
    <Button
        Name="VideoReminder"
        Content="Reminder"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        Click="VideoReminder_Click" />
    <Button
        Name="Tasks"
        Content="Tasks"
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        Visibility="Collapsed"
        Click="Tasks_Click"/>
</StackPanel>

 

The new Video page has a Reminder button, so implement the Reminder code, just as you did for the Blog page,

private void VideoReminder_Click( 
    object sender, RoutedEventArgs e )
{
    Reminder r = new Reminder( "VideoTask" );
    r.Title = "Video Reminder";
    r.Content = "Record video entry on navigation";
    r.BeginTime = DateTime.Now.AddSeconds( 15 );
    r.NavigationUri = NavigationService.CurrentSource;

    ScheduledActionService.Add( r );

}

 

If we navigate to this page directly, making it the first page, we’ll want to make the new button visible, and we’ll want to use the new button to navigate back to the MainPage.  If we get to Videos from the MainPage, however, we do not want the button to be visible.

We can check how we got to the page by overriding OnNavigatedTo.  If we navigated her from another page (e.g., the MainPage), then CanGoBack will be true; but if we got here directly from the reminder then CanGoBack will be false.

protected override void OnNavigatedTo( 
    System.Windows.Navigation.NavigationEventArgs e )
{
    if (NavigationService.CanGoBack != true)
        Tasks.Visibility = System.Windows.Visibility.Visible;
}

 

If we make the Tasks button visible then we need to handle the click event,

protected void Tasks_Click( 
    object sender, RoutedEventArgs e )
{
    NavigationService.Navigate ( 
        new Uri("/MainPage.xaml?clear=true", 
          UriKind.Relative));
}

 

Notice that we are passing a flag in with the navigation Uri (clear = true).  We can test for that in MainPage.xaml to determine whether we returned using this mechanism. If so, we want to remove the Video page from the Back Stack (clicking back from MainPage should exit, not take you back to Video).

To do so, we override OnNavigatedTo in MainPage,

protected override void OnNavigatedTo( 
    System.Windows.Navigation.NavigationEventArgs e )
{
    if (e.NavigationMode == 
        System.Windows.Navigation.NavigationMode.New &&
        NavigationContext.QueryString.ContainsKey( "clear" ))
           NavigationService.RemoveBackEntry();
}

 

Try it out. Navigate to Blog, set a reminder, exit the program.  When the reminder fires, click to return to Blog and then hit the back key. Oops, you exit the application.

Next, try the same with Video, but this time when you return to the Reminder page, note the Tasks button. Click that to return to the first page.  From there, click on back, and note that you (properly) leave the application.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Essentials, Mango, Mini-Tutorial, Patterns & Skills, WindowsPhone and tagged . Bookmark the permalink.

2 Responses to Managing the Back Stack

Comments are closed.