Download the Code Sample
Silverlight Windows Phone applications have a Web-like page model where the end users navigate from one page to another. There’s a dedicated hardware Back button to easily navigate back to previous pages (without consuming screen real estate), and the journaling (or history) of your navigation is integrated with the platform to ease navigating or transitioning across different applications. This two-part article will:
The Windows Phone navigation model consists of a frame (PhoneApplicationFrame) and one or more pages (PhoneApplicationPage) that hold the content loaded into the frame.
The PhoneApplicationFrame exposes most of the navigation events and exposes the Navigate method you’ll use to go across pages. It also determines the client area for the application and reserves the space for the application bar and the system tray.
PhoneApplicationPage has page-specific notifications for when a page is navigated to and when a user navigates away from a page. It also handles the events related to the hardware Back button.
Both PhoneApplicationFrame and PhoneApplicationPage share a NavigationService; this service is actually doing the navigation. Windows Phone supports journaling (tracking the history of the pages you’ve loaded so you can go back to a previous page) and exposes APIs so you can go back. Forward navigation isn’t supported on the phone.
Windows Phone has three dedicated hardware buttons: Back, Start and Search. There are specific application-certification requirements around handling of the hardware Back button:
In addition to the Back button’s critical role in navigation, the Start button also participates in navigation. When the user presses the Start button, the running application is deactivated and a context switch is performed as you navigate forward to the Start menu. From here a user can launch another application and navigate within the new application, or he can choose to navigate back (using the hardware Back button) to the previously running application. This effectively creates a navigation model where the Back button navigates through the pages of a running application or through the stack of previously running application.
As noted earlier, the core players for navigation are PhoneApplicationFrame and PhoneApplicationPage.
PhoneApplicationFrame acts as the RootVisual for the application. At startup, a PhoneApplicationFrame is instantiated in the App class in App.xaml.cs (see Figure 1).
Figure 1 Instantiation of RootFrame in App.xaml.cs
private void InitializePhoneApplication()
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
The runtime automatically navigates to the instance of PhoneApplicationPage, which is specified by the NavigationPage attribute in the DefaultTask on the WMAppManifest.xml application manifest, as shown here:
<DefaultTask Name ="_default" NavigationPage="MainPage.xaml"/>
Getting a bit closer to responsibilities and APIs, PhoneApplicationFrame exposes most of the navigation methods and events we’ll need for this article. Figure 2 lists the most relevant methods, properties and events in PhoneApplicationFrame.
Figure 2 PhoneApplicationFrame Methods, Properties and Events
Most are inherited from Frame, so for those familiar with the Silverlight Frame class, these methods should look familiar. The list in Figure 2 isn’t inclusive of all PhoneApplicationFrame features, just the relevant ones for navigation.
Code Walk-Through: To see all these events and properties in action, explore AllNavigationsEvents.xaml.cs in the sample code accompanying this article. You can also see the order in which events fire in Figure 3.
Figure 3 The Sequence of Events as You Navigate Across Pages
PhoneApplicationFrame also determines the client area that the application will get and reserves the space for the application bar and the system tray. This detail will be relevant as we navigate across pages that have an application bar because it’s specified at the page level, and there’s a system-wide animation to show and hide the application bar as a page gets loaded.
The second participant in the navigation is PhoneApplicationPage. It plays two critical roles in navigation:
For integration with the hardware Back button, PhoneApplicationPage exposes a BackKeyPress event. The page also has a virtual OnBackKeyPress method you can override in your instance of a page to handle and even cancel a Back button press event.
PhoneApplicationFrame has a Navigating event and an OnNavigatingFrom notification/callback. Within both of these, you can cancel navigations to other pages within the app by setting e.Cancel = true in the NavigationCancelEventArgs parameter passed to these methods; due to a known bug on the platform, you shouldn’t cancel Back button navigations from these events/methods. If you do cancel a hardware Back button press in this event, your navigation will break and the application will need to be restarted. The only two recommended methods for canceling a hardware Back button press are the PhoneApplicationPage BackKeyPress event and the OnBackKeyPress callback.
See Figure 4 for a list of events and methods where navigations can be canceled, with recommendations on whether a Back press can be canceled in that method, and advice on how to check if the event was a back navigation.
Figure 4 Events and Methods Where Navigations Can Be Canceled
PhoneApplicationPage complements these events to complete the navigation lifecycle with the more useful OnNavigatedTo and OnNavigatedFrom method callbacks for the page. To better understand and easily remember when these callbacks are called, it’s best to complete their method names with a “this page.” One method is called when the user has “navigated to this page,” and later the other method gets called when the user is “navigated from this page” onto another page.
Figure 3 shows the sequence of events as you navigate across pages. The symmetry between NavigatedTo/NavigatedFrom makes these two methods ideal for starting and stopping work that’s required when the page is visible, but not required when the page is in the back stack. Also notice that NavigatedTo always fires before a page is loaded, so don’t assume the contents of the page are loaded at this time.
The reason OnNavigatedTo and OnNavigatedFrom are critical to Windows Phone is because of the back stack. The OS maintains the back stack for pages you can go back to, so pages aren’t immediately unloaded, destroyed or garbage collected when a navigation happens from one page to another. Instead, the pages are moved to the back stack and kept alive (in memory), and when the user clicks back to get to that page, the page is simply added back into the visual tree. The page isn’t recreated (unless the application has been deactivated and tombstoned between when the user left the page and clicked back). Because forward journaling isn’t supported, pages are eligible for garbage collection when you navigate from a page back to the previous page—assuming there are no other references to this page.
Figure 5 shows a diagram that illustrates a PhoneApplicationPage lifecycle.
Figure 5 The PhoneApplicationPage Lifecycle
As you navigate from Page1 to Page2 and then Page3, pages aren’t garbage collected until you call the GoBack method from the page. Inactive pages are in the back stack, but still in memory. If these pages are listening to global events, the event listeners are still active.
Despite a page not getting garbage collected when you navigate from it, the page is no longer visible or active until you navigate back to it, so you should make sure you do any cleanup and release any expensive resources when the user has navigated away from a page. For example, if you’re listening to location changes using GeoCoordinateWatcher, you should stop the listener on the OnNavigatedFrom and restart it when the user navigates back to your page–and your page OnNavigatedTo is called.
Code Walk-Through: To see how pages are retained in memory while they’re in the back stack, explore the GarbageCollectedSample page included in the accompanying code download. It keeps a running tally of pages in memory, and you can see it increase as you navigate forward and decrease as you navigate back from a page.
That wraps up the first part of our series. Next month, we’ll focus on advanced navigation topics.
Yochay Kiriaty is a senior technical evangelist at Microsoft, focusing on client technologies such as Windows and Windows Phone. He coauthored the books “Introducing Windows 7 for Developers” (Microsoft Press, 2009) and “Learning Windows Phone Programming” (O’Reilly Media, 2011).
Jaime Rodriguez is a principal evangelist at Microsoft driving adoption of emerging client technologies such as Silverlight and Windows Phone. You can reach him on Twitter: @jaimerodriguez or on blogs.msdn.com/jaimer.
Thanks to the following technical expert for reviewing this article: Peter Torr
Hi, I've been looking into the GarbageCollectedSample as I've been having quite a few problems myself getting my pages garbage collected. Unfortunately trying the sample displays similar issues as what I see on my own project. When I click "Navigate to new instance" the instance counter correctly counts up, but as I click the back button I see that maximum one (old) page gets collected. As a result of clicking "Navigate to new instance" 10 times, the page reads: instance 11, 11 active...(This makes sense since I didn't count entering the page in the first place. Now when I start navigating back I get the following: Back 1: 10 - 11 active Back 2: 9 - 10 active...so far so good Back 3: 8 - 10 active...hmm Back 4: 7 - 10 active Back 5: 6 - 10 active Back 6: 5 - 10 active Back 7: 4 - 10 active Back 8: 3 - 10 active Back 9: 2 - 10 active Back 10: 1 - 10 active Clearly only the one of the pages got GC'ed. The article clearly states: Because forward journaling isn’t supported, pages are eligible for garbage collection when you navigate from a page back to the previous page—assuming there are no other references to this page. I couldn't find any reference mentioning forward journaling being supported in 7.1. Does anyone have an idea what's happing? Ps. I'm using the WP7.1 SDK and judging by the sample this article was written for 7.0, but I don' think 7.1 introduces any changes here?
The Description column for GoBack reads: "always check CanGoForward before calling this method." Should this read "always check CanGoBack before calling this method?"
More MSDN Magazine Blog entries >
Browse All MSDN Magazines
Subscribe to MSDN Flash newsletter
Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.