author | Description | title | ms.assetid | label | template | op-migration-status | ms.author | ms.date | ms.topic | ms.prod | ms.technology | keywords | ms.localizationpriority |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
serenaz |
Learn how to enable peer-to-peer navigation between two basic pages in an Universal Windows Platform (UWP) app. |
Peer-to-peer navigation between two pages |
0A364C8B-715F-4407-9426-92267E8FB525 |
Peer-to-peer navigation between two pages |
detail.hbs |
ready |
sezhen |
05/19/2017 |
article |
windows |
uwp |
windows 10, uwp |
medium |
Learn how to use a frame and pages to enable basic peer-to-peer navigation in your app.
Important APIs: Windows.UI.Xaml.Controls.Frame class, Windows.UI.Xaml.Controls.Page class, Windows.UI.Xaml.Navigation namespace
- On the Microsoft Visual Studio menu, choose File > New Project.
- In the left pane of the New Project dialog box, choose the Visual C# > Windows > Universal or the Visual C++ > Windows > Universal node.
- In the center pane, choose Blank App.
- In the Name box, enter NavApp1, and then choose the OK button. The solution is created, and the project files appear in Solution Explorer.
- To run the program, choose Debug > Start Debugging from the menu, or press F5. A blank page is displayed.
- To stop debugging and return to Visual Studio, exit the app, or click Stop Debugging from the menu.
Next, add two pages to the project.
- In Solution Explorer, right-click the BlankApp project node to open the shortcut menu.
- Choose Add > New Item from the shortcut menu.
- In the Add New Item dialog box, choose Blank Page in the middle pane.
- In the Name box, enter Page1 (or Page2) and press the Add button.
- Repeat steps 1-4 to add the second page.
Now, these files should be listed as part of your NavApp1 project.
C# | C++ |
---|---|
|
|
In Page1.xaml, add the following content:
- A TextBlock element named
pageTitle
as a child element of the root Grid. Change the Text property toPage 1
.
<TextBlock x:Name="pageTitle" Text="Page 1" />
- A HyperlinkButton element as a child element of the root Grid and after the
pageTitle
TextBlock element.
<HyperlinkButton Content="Click to go to page 2"
Click="HyperlinkButton_Click"
HorizontalAlignment="Center"/>
In the Page1.xaml code-behind file, add the following code to handle the Click
event of the HyperlinkButton you added to navigate to Page2.xaml.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(Page2));
}
void Page1::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page2::typeid));
}
In Page2.xaml, add the following content:
- A TextBlock element named
pageTitle
as a child element of the root Grid. Change the value of the Text property toPage 2
.
<TextBlock x:Name="pageTitle" Text="Page 2" />
- A HyperlinkButton element as a child element of the root Grid and after the
pageTitle
TextBlock element.
<HyperlinkButton Content="Click to go to page 1"
Click="HyperlinkButton_Click"
HorizontalAlignment="Center"/>
In the Page2.xaml code-behind file, add the following code to handle the Click
event of the HyperlinkButton to navigate to Page1.xaml.
[!div class="tabbedCodeSnippets"]
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(Page1));
}
void Page2::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page1::typeid));
}
Note
For C++ projects, you must add a #include
directive in the header file of each page that references another page. For the inter-page navigation example presented here, page1.xaml.h file contains #include "Page2.xaml.h"
, in turn, page2.xaml.h contains #include "Page1.xaml.h"
.
Now that we've prepared the pages, we need to make Page1.xaml display when the app starts.
Open the App.xaml code-behind file and change the OnLaunched
handler.
Here, we specify Page1
in the call to Frame.Navigate instead of MainPage
.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(Page1), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
{
auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
rootFrame = ref new Frame();
rootFrame->NavigationFailed +=
ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(
this, &App::OnNavigationFailed);
if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window::Current->Content = rootFrame;
}
if (rootFrame->Content == nullptr)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page1::typeid), e->Arguments);
}
// Ensure the current window is active
Window::Current->Activate();
}
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, build and run the app. Click the link that says "Click to go to page 2". The second page that says "Page 2" at the top should be loaded and displayed in the frame.
Before we add more functionality to our app, let's look at how the pages we added provide navigation within our app.
First, a Frame called rootFrame
is created for the app in the App.OnLaunched
method in the App.xaml code-behind file. The Frame class supports various navigation methods such as Navigate, GoBack, and GoForward, and properties such as BackStack, ForwardStack, and BackStackDepth.
The Navigate method is used to display content in this Frame. By default, this method loads MainPage.xaml. In our example, Page1
is passed to the Navigate method, so the method loads Page1
in the Frame.
Page1
is a subclass of the Page class. The Page class has a read-only Frame property that gets the Frame containing the Page. When the Click event handler of the HyperlinkButton in Page1
calls this.Frame.Navigate(typeof(Page2))
, the Frame displays the content of Page2.xaml.
Finally, whenever a page is loaded into the frame, that page is added as a PageStackEntry to the BackStack or ForwardStack of the Frame, allowing for history and backwards navigation.
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 Page1.xaml, replace the the HyperlinkButton you added earlier with the following StackPanel.
Here, we add a TextBlock label and a TextBox name
for entering a text string.
<StackPanel>
<TextBlock HorizontalAlignment="Center" Text="Enter your name"/>
<TextBox HorizontalAlignment="Center" Width="200" Name="name"/>
<HyperlinkButton Content="Click to go to page 2"
Click="HyperlinkButton_Click"
HorizontalAlignment="Center"/>
</StackPanel>
In the HyperlinkButton_Click
event handler of the Page1.xaml code-behind file, add a parameter referencing the Text
property of the name
TextBox to the Navigate
method.
[!div class="tabbedCodeSnippets"]
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(Page2), name.Text);
}
void Page1::HyperlinkButton_Click(Platform::Object^ sender, RoutedEventArgs^ e)
{
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Page2::typeid), name->Text);
}
In Page2.xaml, replace the HyperlinkButton you added earlier with the following StackPanel.
Here, we add a TextBlock for displaying the text string passed from Page1.
<StackPanel>
<TextBlock HorizontalAlignment="Center" Name="greeting"/>
<HyperlinkButton Content="Click to go to page 1"
Click="HyperlinkButton_Click"
HorizontalAlignment="Center"/>
</StackPanel>
In the Page2.xaml code-behind file, add the following to override the OnNavigatedTo
method:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter))
{
greeting.Text = $"Hi, {e.Parameter.ToString()}";
}
else
{
greeting.Text = "Hi!";
}
base.OnNavigatedTo(e);
}
void Page2::OnNavigatedTo(NavigationEventArgs^ e)
{
if (dynamic_cast<Platform::String^>(e->Parameter) != nullptr)
{
greeting->Text = "Hi," + e->Parameter->ToString();
}
else
{
greeting->Text = "Hi!";
}
::Windows::UI::Xaml::Controls::Page::OnNavigatedTo(e);
}
Run the app, type your name in the text box, and then click the link that says Click to go to page 2.
When the Click event of the HyperlinkButton in Page1
calls this.Frame.Navigate(typeof(Page2), name.Text)
, the name.Text
property is passed to Page2
, and the value from the event data is used for the message displayed on the page.
Page content and state is not cached by default, so if you'd like to cache information, you must enable it in each page of your app.
In our basic peer-to-peer example, there is no back button (we demonstrate back navigation in backwards navigation), but if you did click a back button on Page2
, the TextBox (and any other field) on Page1
would be set to its default state. One way to work around this is to use the NavigationCacheMode property to specify that a page be added to the frame's page cache.
In the constructor of Page1
, you can set NavigationCacheMode to Enabled to retains all content and state values for the page until the page cache for the frame is exceeded. Set NavigationCacheMode to Required if you want to ignore CacheSize limits, which specify the number of pages in the navigation history that can be cached for the frame. However, keep in mind that cache size limits might be crucial, depending on the memory limits of a device.
public Page1()
{
this.InitializeComponent();
this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
}
Page1::Page1()
{
this->InitializeComponent();
this->NavigationCacheMode = Windows::UI::Xaml::Navigation::NavigationCacheMode::Enabled;
}
- Navigation design basics for UWP apps
- Guidelines for tabs and pivots
- Guidelines for navigation panes