The Windows Phone platform offers several mechanisms for preserving your application’s state…the key is knowing which one to use when, and why. I’m going to try to provide some guidance to help answer those questions.
First things first – there are 3 key mechanisms provided for saving application state on the phone (4 if you count writing to some kind of cloud storage, but that’s beyond the scope of this discussion.) There are two state dictionaries, which under the right circumstances are saved and restored automatically, and then there is IsolatedStorage. This discussion will explore the uses of each one, with this post focusing on the Page State Dictionary.
The Page State Dictionary
This is by far the narrowest in scope of the 3 state-saving mechanisms. It is implemented as an IDictionary<String, Object>, and is accessible through a PhoneApplicationPage’s State property. To be stored in this collection, the objects that are placed must be serializable. There is also a limitation of how much data can be stored using this mechanism, with up to 2MB available per page and up to 4MB available for the entire application.
The contents of the Page State Dictionary can only be accessed within or after the page’s OnNavigatedTo method has been called and within or before the page’s OnNavigatedFrom method has been called. Any attempt to access the contents outside of these times (for example in the page’s constructor) will result in an InvalidOperationException being thrown.
Outside of these limitations, use of the Page State Dictionary is quite straightforward. When leaving the page (or any time prior), the data to be retained is written to the Page State Dictionary:
protected override void OnNavigatedFrom(NavigationEventArgs e)
State[“UserStateData”] = UserStateTextBox.Text;
State[“UserStateData”] = UserStateTextBox.Text;
When returning to the page, the Page State Dictionary is interrogated for the value and, if present, the value is applied to the control.
protected override void OnNavigatedTo(NavigationEventArgs e)
UserStateTextBox.Text = (String)State["UserStateData"];
To understand when the Page State Dictionary is useful (necessary?), it is important to understand the Page navigation model in Windows Phone applications. To that end, a simple application is used, consisting of 3 pages. Page 1 and Page 2 each include a button that navigates to the next page. The second page (pictured below) includes 2 textboxes and the overrides for the OnNavigatedFrom and OnNavigatedTo methods listed above, which persist and retrieve the value of only the first textbox into/from the Page State Dictionary.
When switching between pages using the Navigate method from the NavigationService class, a new instance is created of the page defined by the Xaml file referenced in the method’s “source” parameter. This happens every time. When doing explicit navigation (eg – a Url is provided to the Navigate method), a new page instance is created. Figure 2 illustrates this concept of new page instance creation.
- The “Go to Page 2” button is used from Page 1 to Navigate to Page 2 with the code NavigationService.Navigate(new Uri(“/Page2.xaml”, UriKind.Relative));
- This first instance of Page 2 is created with its own Page State Dictionary. The user enters the phrase “User State 1” into the first textbox and “User State 2” into the second textbox, and following the OnNavigatedFrom code above, the value of the first textbox is put into the Page State Dictionary when the user uses the Back Button to navigate back to Page 1.
- Now the user presses the “Go to Page 2” button again. This causes a completely new instance of Page 2 to be created, with its own Page State Dictionary. The value placed in the previous Page 2 instance’s Page State Dictionary is not preserved, resulting in both textboxes being empty.
Conversely, using either the Back Button or the NavigationService.GoBack method to navigate back to a page in the phone’s Back-Stack will not create a new instance of the page, but will instead use the original instance (there is an important exception to this, which will be discussed momentarily.) This is illustrated in Figure 3.
- The “Go to Page 3” button is used from Page 2 to navigate to Page 3. In the OnNavigatedFrom method, the value of the first textbox is put into the Page State Dictionary.
- The first instance of Page 3 is created. The user uses the Back Button to navigate back to Page 2.
- The original instance of Page 2 is displayed, with the text in both textboxes still being displayed (even though only one textbox’s value was put into and retrieved from the Page State Dictionary.)
It is worth noting that there is no Forward button to complement the Back button on Windows Phone devices, and calls to the NavigationService.GoForward method will result in an exception.. This is because the current version of the Windows Phone does not maintain any “Forward Stack.”
So, if the Page State Dictionary is specific to an instance of a PhoneApplicationPage object and cannot be used for repeated explicit navigations to a specific page (as seen in Figure 1), and during navigation using GoBack or the BackButton, it has no effect on whether or not state is preserved (as seen in Figure 2), what good is it? The answer revolves around Tombstoning.
Tombstoning is the process in the Phone Application lifecycle where one application is terminated anytime another application is launched. A full treatment of Tombstoning is beyond the scoped of this discussion, but further information is available at http://msdn.microsoft.com/en-us/library/ff817008%28v=VS.92%29.aspx. The key concept to be aware of is that when an application is tombstoned, it is terminated and any in-memory state information is lost except for what was written to the State Dictionaries and any information written to disk via Isolated Storage. Likewise, an application that has been tombstoned can be reactivated when its entry in the Back Stack is reached using the phone’s Back Button (or via a Chooser action, as will be seen is a subsequent post.) The Page State Dictionary provides a mechanism for restoring a page’s state when it is re-invoked after the application has been tombstoned. This process is illustrated in Figure 4.
- The “Go to Page 3” button is used from Page 2 to Navigate to Page 3. In the OnNavigatedFrom method, the value of the first textbox is put into the Page State Dictionary (same as the previous example.)
- The first instance of Page 3 is created. The user launches another application (via pressing the Start or Search Buttons on the Phone, etc.) This tombstones the current application.
- The user finishes using the other application and presses the Back Button, re-activating the tombstoned application and creating a new instance of Page 3
- The user presses the Back button to go back to Page 2. A new instance of Page 2 is created, but it does have access to the original Page State Dictionary.
- The value of the first textbox (“User State 1”) is rehydrated from the entry in the Page State Dictionary during the OnNavigatedTo method. The data entered into the second text box is lost.
So in the end, the main reason to use the Page State Dictionary is to restore the state of the page when navigating Back to that page either immediately or at some point after the application has been tombstoned. However, if the application is tombstoned as a result of invoking a Chooser, things may be quite different, as will be seen in the follow-up to this post, which will go over the Application State Dictionary.