Quickstart: Navigating between pages (Windows Store apps using C#/VB/C++ and XAML)
This topic discusses basic navigation concepts and demonstrates how to create an app that navigates between two pages.
Roadmap: How does this topic relate to others? See:
You can create multiple pages for your Windows Store app and support the user navigating between the pages within the app, similar to how you navigate through pages on a single website. Microsoft Visual Studio has page templates that provide basic navigation support for Windows Store apps using C# or Microsoft Visual Basic. In this topic, we use the page templates to create a simple app that supports navigation.
When we discuss navigation for Windows Store apps, we mean navigating between pages within an app, not navigating between apps.
This topic assumes that you can create a basic Windows Store app using C# or Visual Basic. For instructions on creating your first Windows Store app, see Create your first Windows Store app using C# or Visual Basic.
Creating the blank app
- On the Visual Studio menu, choose File > New Project.
- In the left pane of the New Project dialog box, choose the Visual C#, Visual Basic, or Visual C++ node.
- In the center pane, choose Blank App.
- In the Name box, enter BlankApp, and then choose the OK button.
The solution is created and the project files appear in Solution Explorer. For more info about the project files, see C#, VB, and C++ project templates for Windows Store apps.
Important When you run Visual Studio for the first time, it prompts you to obtain a developer license. For more info, see Get a developer license.
- To run the program, on the Visual Studio menu, choose Debug > Start Debugging, or press F5.
A blank page is displayed.
- Press Shift+F5 to stop debugging and return to Visual Studio.
Next, add two pages to the project. These act as the pages we navigate between. Do the following steps two times to add two pages.
Adding the basic page
- In Solution Explorer, open the shortcut menu for the BlankApp project node, and then choose Add > New Item.
- In the Add New Item dialog box, choose Blank Page in the middle pane.
- In the Name box, enter page1 (or page2) and choose the Add button.
After you have done the previous steps two times, the following files should have been added to your project.
- BasicPage1.xaml.cs or BasicPage1.xaml.vb
- BasicPage2.xaml.cs or BasicPage2.xaml.vb
Now we need to use the pages we added in the app. Make the following changes to BasicPage1.xaml.
Make the following changes to BasicPage2.xaml.
Add the following code to the
BasicPage1 class in BasicPage1.xaml.cs or BasicPage1.xaml.vb.
Private Sub HyperlinkButton_Click(sender As Object, e As RoutedEventArgs) Me.Frame.Navigate(GetType(BasicPage2)) End Sub
Now that we've prepared the new pages, we need to make
BasicPage1 the first thing that appears when the app starts. Open app.xaml.cs/vb and change the
OnLaunched method to call Frame.Navigate by using
BasicPage1 instead of
BlankPage. The relevant line of code looks like this:
Note The code here uses the return value of Navigate to throw an app exception if the navigation to the app's initial window frame fails. When Navigate returns true, the navigation happens.
Now you are ready to test the app. Start the app, and click the link that says Click to go to page 2. The second page should appear that says "Page 2" at the top. Notice that there is a back button to the left of the page title. Click the button to return to the first page.
Before we add more functionality to our app, let's look at how the pages we added provide navigation support for the app.
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") ).
The Frame class is primarily responsible for navigation and implements methods such as Navigate, GoBack, and GoForward. You use the Navigate method to display content in the Frame. In the previous example, the
App.OnLaunched method creates a Frame and passes
BasicPage1 to the Navigate method. Then the method sets the content of the app's current window to the Frame. The result is that the app's window contains a Frame that contains
BasicPage1 is a subclass of the Page class. The Page class has a Frame property, a read-only property that gets the Frame that contains the Page. When the Click event handler of the HyperlinkButton calls
Frame.Navigate(typeof(BasicPage2)), the Frame in the app's window displays the content of
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 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.
SuspensionManagerprovides the KnownTypes collection which passes the types in the collection to the DataContractSerializer. As the
SuspensionManageris 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.
- 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.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.
SuspensionManageris wrapped in the implementation of NavigationHelper.
NavigationHelper is an implementation of a page that provides the following important conveniences:
- Event handlers for Navigate, GoBack, and GoForward.
- Mouse and keyboard shortcuts for navigation.
- State management for navigation and process lifetime management.
In addition to providing the implementations described, 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.
- Any data that is stored in the individual page must be available to be serialized by the DataContractSerializer.
- 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.
When we created the navigation pages, we used the Basic Page template. This template, and other templates that support navigation, creates a page that provides a Back button in the top left corner of the page. The button is styled to be visible only when the button is enabled. This is why you don't see the Back button on the first page but you see it on the second page.
The following page templates offer this same navigation support.
- Basic Page
- Group Detail Page
- Grouped Items Page
- Item Detail Page
- Items Page
- Split Page
- Hub Page
- Search Results Page
Our app navigates between two pages, but it really doesn't do anything interesting yet. Often, when an app has multiple pages, the pages need to share information. Let's pass some information from the first page to the second page.
In BasicPage1.xaml, replace the StackPanel that you added earlier with this XAML.
<StackPanel Grid.Row="1" Margin="120,0,120,60"> <TextBlock Text="Enter your name"/> <TextBox Width="200" HorizontalAlignment="Left" Name="tb1"/> <HyperlinkButton Content="Click to go to page 2" Click="HyperlinkButton_Click"/> </StackPanel>
In BasicPage1.xaml.cs or BasicPage1.xaml.vb, replace the
HyperlinkButton_Click event handler with the following code.
Private Sub HyperlinkButton_Click(sender As Object, e As RoutedEventArgs) Me.Frame.Navigate(GetType(BasicPage2), tb1.Text) End Sub
In BasicPage2.xaml.cs or BasicPage2.xaml.vb, fill in the empty navigationHelper_LoadState method with this:
Private Sub navigationHelper_LoadState((e As NavigationHelper.LoadStateEventArgs) Dim name As String = TryCast(e.NavigationParameter, String) If Not String.IsNullOrWhiteSpace(name) Then tb1.Text = "Hello, " & name Else tb1.Text = "Name is required. Go back and enter a name." End If End Sub
Run the app, type your name in the text box, and then click the link that says Click to go to page 2. When you called
this.Frame.Navigate(typeof(BasicPage2), tb1.Text); in the Click event of the HyperlinkButton, the
tb1.Text property is passed when
BasicPage2 loads. Then, the
navigationHelper_LoadState method of
BlankPage2 gets the value from the event data and uses it to display a message.
When you ran the last example, you might have noticed that if you click the Back button on
BasicPage2, the TextBox on
BasicPage1 is empty when it appears. Let's suppose that the user of the app wants to go back and make a change on the previous page. If
BasicPage1 had many fields to fill in, the user would not be happy to see reset fields when the app went back to that page. You can specify that a page be cached by using the NavigationCacheMode property. In the constructor of
BasicPage1, set NavigationCacheMode to Enabled.
Sub New() InitializeComponent() ... Me.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled End Sub
Now when you run the app and navigate from
BasicPage2 back to
BasicPage1, the TextBox on
BasicPage1 retains its value.
In this topic you learned how to create a simple app that navigates between pages. You learned how to pass information from one page to another and also how to specify that a page's state should be cached.
- Examining the navigation stack (BackStack, ForwardStack)
- Checking CanGoBack or CanGoForward and using these as triggers to hide or show navigation UI
- More about caching pages, GetNavigationState, CacheSize
- Canceling a navigation, and the Navigating event
Build date: 11/26/2013