Navigation model (using C#/VB/C++ and XAML)

The navigation model used in the Hub App, Grid App, and Split App project templates is the recommended navigation model for Windows Store apps built using XAML. This model creates a central frame as the content of the default Window, and then users navigate to other pages using that frame. The single-frame navigation model provides a smoother, app-like transition between pages, and also makes it easier for you to manage program state. For more info on navigation and an example of using the built-in navigation in a Windows Store app built using XAML, see QuickStart: using single page navigation.

Important  The information in this topic has been updated for Microsoft Visual Studio 2013.

The file App.xaml.cs/vb/cpp creates a Frame, if one doesn't already exist, and makes the Frame the content of the current Window. If the content of the frame is null, the app navigates to the home page as specified in the code behind App.xaml. For example, in the the Grid App, the code is rootFrame.Navigate(typeof(GroupedItemsPage), "AllGroups") ).

During setup, SuspensionManager registers the Frame. SuspensionManager is a helper class provided in the Common folder in the Grid App or Split App template and provides the implementation used to store and load state when the app is terminated.

All apps move through an application lifecycle as dictated by the operating system. Whenever an app is terminated by the system for reasons such as resource constraints, shut down, reboot, and so forth, you as the developer must restore data upon resuming the app. SuspensionManager is provided to help you with this task.

SuspensionManager captures global session state to simplify process lifetime management for an application. Session state is automatically cleared under a variety of conditions and should be used only to store information that would be convenient to carry across sessions, but that should be discarded when an application crashes or is upgraded. This basically includes transient UI data.

SuspensionManager has two properties: SessionState and KnownTypes.

  • SessionState provides access to global session state for the current session. This state is serialized by the SaveAsync method and is restored by the RestoreAsync method. All data is saved and restored using DataContractSerialization and should be as compact as possible. Strings are other self-contained data types are strongly recommended.
  • KnownTypes stores a list of custom types provided to the DataContractSerializer that is used by the SaveAsync and RestoreAsync methods when reading and writing session state. Initially empty, additional types may be added to customize the serialization process.

SuspensionManager stores state in a dictionary, SessionState. The dictionary stores FrameState against a key that is uniquely bound to a Frame. Each FrameState dictionary holds state for each page in the navigation state for that particular frame. Each page stores the navigation parameter as well as any other state that the user decides to add.

Here is how that works: When a Frame is created, if you want the state to be stored for that frame it should immediately be registered. They are registered with the following call (SuspensionManager.RegisterFrame(rootFrame, "AppFrame")). Each frame should have a unique key associated with it. Generally most apps will only have a single frame. If you declare a second frame, it'll need to be registered as well. When a frame is registered, two attached properties are set on the frame. First is the key that you have associated with the frame, and second is the dictionary of session state that will be associated with the frame. Frames that have been previously registered will immediately have their navigation and state restored. Frames can be unregistered as well; all navigation state and history will be discarded.

And now for the important calls: SaveAsync and RestoreAsync. SaveAsync is used to save the entire SessionState. All frames that have been registered via SuspensionManager.RegisterFrame will also preserve their current navigation stack, which in turn gives their active page an opportunity to save its data. The SessionState is then serialized using a DataContractSerializer and written to a file stored in the local folder as defined by the ApplicationData.

RestoreAsync is used to read in the previously saved SessionState. All frames that have been registered with RegisterFrame will also restore their prior navigation state, which will give their active page an opportunity to restore its state. Again as in SaveAsync, a DataContractSerializer is used to de-serialize the state stored in a file in the Application’s local folder.

There are two common errors that people hit when attempting to store the state of their app.

  • The types stored by individual pages must be able to be serialized by the DataContractSerializer in C# and VB. To do this any custom type must be registered before it can be saved or restored. SuspensionManager provides the KnownTypes collection which passes the types in the collection to the DataContractSerializer. As the SuspensionManager is called to restore state in the OnLaunched override of the code behind for App.xaml, a good place to register types is in the app constructor.

            public App()
            {
                this.InitializeComponent();
                this.Suspending += OnSuspending;
                SuspensionManager.KnownTypes.Add(typeof(MyCustomType));
            }
    
  • The parameters passed in using navigation must be able to be serialized by the platform. When we are saving and restoring the navigation stack, we call Frame.GetNavigationState() and Frame.SetNavigationState(). Both of these calls make use of an internal serialization format and all types passed as the parameter in Frame.Navigate() must be able to be serialized by the platform.

The use of SuspensionManager is wrapped in the implementation of NavigationHelper.

NavigationHelper is an implementation of a page that provides the following important conveniences:

  • Event handlers for GoBack, GoForward, and GoHome.
  • Mouse and keyboard shortcuts for navigation.
  • State management for navigation and process lifetime management.

Default View Model

The DefaultViewModel is used by every Complex Page Item Template. The DataContext is bound to the DefaultViewModel defined on the page itself: DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}". The DefaultViewModel property is of type ObservableDictionary, which is a map of the Strings (keys) to objects (values). The DefaultViewModel is provided as a convenience and can be changed to a strongly typed view model, if necessary.

Each page is then bound to properties that are meant to be set on the DefaultViewModel in the code behind. Take for example the GroupedItemsPage. On this page the CollectionViewSource has the Source property bound to the property Groups (Source="{Binding Groups}". Groups is a key of a key,value pair stored in the DefaultViewModel (this.DefaultViewModel["Groups"] = sampleDataGroups;).

Application view state to visual state mapping

In the templates provided for Windows 8, LayoutAwarePage provided code to handle view state, but this code is not required in Windows 8.1. Only the SplitPage and the FileOpenPicker page include code to handle view state. Each page is now expected to handle all Window sizes where the width is at least 500px.

NavigationHelper registers commands for GoBack and GoForward. These implementations check if there is a Frame associated with the page and, if there is, if the frame can go back or forward before calling Frame.GoBack() or Frame.GoForward(). This can be overridden to change the default behavior as occurs in the Split Page.

NavigationHelper also registers the common mouse and keyboard shortcuts that are typically used for navigating. The back mouse button, “ALT + Left arrow key,” and the previous keyboard key are used to navigate back. The next mouse button, “ALT + Right arrow key,” and the next keyboard key are used to navigate forward.

Process Lifetime Management

In addition to providing the implementations described earlier, NavigationHelper also needs to be called from the OnNavigatedTo() and OnNavigatedFrom() event handlers that are implemented on each page. When these events occur, NavigationHelper calls a page-specific implementation of LoadState() and SaveState(). You can customize the implementation of these functions on each page. They should be used in place of OnNavigatedTo() and OnNavigatedFrom() respectively.

OnNavigatedFrom() is called when the page is about to be displayed in a Frame. When we are navigating to a new page we load state associated with the page. If the page is being restored, the state that was previously saved for the page is restored. LoadState is then called such that each page can react. LoadState has two parameters; the original navigation parameter passed into OnNavigatedTo and the previous page state if it exists.

OnNavigatedFrom() is called when the page is no longer going to be displayed in a Frame. When we are navigating away from a page, we allow the page to save its current state. An empty dictionary is passed into SaveState(). Each page can override SaveState and store objects in the keyed dictionary (string to object). This dictionary is then associated with the page and added to the SessionState that SuspensionManager keeps track of for the given frame.

Note  

  • Any data that is stored in the individual page must be available to be serialized by the DataContractSerializer. For more info, see the discussion of the SuspensionManager at the beginning of this topic.
  • It is also important to store only transient UI information here, because this state will be lost if the app is closed by any means other than Terminated.

Structure of an app

To understand the structure of an app we'll use an app created with the Grid App project template. The starting place of all Windows Store apps that use XAML is the Application object in App.xaml and the associated code behind. The first code that runs when your app is created is the app constructor. Following this, one of the various activation methods is called; in this case it'll be the OnLaunched event when the app is launched from a tile on the start screen. In this call a Frame is created, any previous state is reloaded (if the app was previously terminated), and then the frame is used to navigate to the first page. When we navigate to a page, the OnNavigatedTo event handler on the page calls the NavigationHelper. The NavigationHelper runs and records the parameters and reloads any previous state information for the given page. It then calls the LoadState() method that is overridden in the GroupedItemsPage. Here data is loaded and the default view model is populated. When we navigate to another page, the OnNavigatedFrom event handler calls NavigationHelper, which saves any state for this page by calling SaveState(). SaveState() is overridden in pages that have transient UI state such as the SplitPage before navigating to the new page and then calling through to the LoadState() method again.

C#, VB, and C++ project templates for Windows Store apps

Part 2: Manage app lifecycle and state

Part 3: Navigation, layout, and views

 

 

Send comments about this topic to Microsoft

Build date: 11/11/2013