Mango From Scratch
In a previous posting, I discussed creating Reminders. One little known feature of 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):
- Blog
- Video
- 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 itself (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.
2 Responses to Managing the Back Stack