重要 API: Windows.UI.Xaml.Controls.Frame 类、 Windows.UI.Xaml.Controls.Page 类、 Windows.UI.Xaml.Navigation 命名空间、 OnNavigatedTo
若要在应用中实现向后导航,请在应用的 UI 左上角放置后退按钮。 用户期望后退按钮导航到应用的导航历史记录中的上一位置。 默认情况下,Frame 控件会在其 BackStack 和 ForwardStack 中记录导航动作。 不过,你可以更改哪些导航操作会被添加到导航历史记录中。
对于具有多个页面的大多数应用,建议使用 NavigationView 控件为应用提供导航框架。 它适应各种屏幕大小,支持顶部和左侧导航样式。 如果你的应用使用 NavigationView 控件,那么你可以使用 NavigationView 的内置后退按钮。
注释
在不使用控件的情况下实现导航 NavigationView 时,应使用本文中的准则和示例。 如果使用 NavigationView,此信息提供了有用的背景知识,但应使用 NavigationView 文章中的特定指导和示例。
“后退”按钮
若要创建后退按钮,请使用带有样式的 Button 控件 NavigationBackButtonNormalStyle ,并将该按钮放置在应用的 UI 左上角(有关详细信息,请参阅下面的 XAML 代码示例)。
<Page>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="BackButton"
Style="{StaticResource NavigationBackButtonNormalStyle}"
IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}"
ToolTipService.ToolTip="Back"/>
</Grid>
</Page>
如果应用具有顶部 CommandBar,请将 Button 控件 CommandBar.Content 置于该区域中。
<Page>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CommandBar>
<CommandBar.Content>
<Button x:Name="BackButton"
Style="{StaticResource NavigationBackButtonNormalStyle}"
IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}"
ToolTipService.ToolTip="Back"
VerticalAlignment="Top"/>
</CommandBar.Content>
<AppBarButton Icon="Delete" Label="Delete"/>
<AppBarButton Icon="Save" Label="Save"/>
</CommandBar>
</Grid>
</Page>
为了尽量减少应用程序中 UI 元素的移动,当返回栈中没有任何内容时,显示一个不可用的后退按钮(IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}")。 但是,如果您预计应用程序不会有返回栈,那么根本不需要显示返回按钮。
针对不同的设备和输入进行优化
此向后导航设计指南适用于所有设备,但如果针对不同的外形规格和输入方法进行优化,用户将受益。 在后退按钮单击之外,建议处理以下事件,以支持最为常见的后退导航输入。
| 事件 / 活动 | 输入 |
|---|---|
| CoreDispatcher.AcceleratorKeyActivated | Alt+左箭头键 VirtualKey.GoBack |
| SystemNavigationManager.BackRequested (系统导航管理器.请求返回) | Windows + Backspace、 游戏手柄B按钮, 平板模式返回按钮 硬件后退按钮 |
| CoreWindow.PointerPressed | VirtualKey.XButton1 (如在一些老鼠身上找到的后退按钮)。 |
代码示例
本部分演示如何使用各种输入处理后退导航。
后退按钮和后退导航
至少需要处理后退按钮 Click 事件并提供执行后退导航的代码。 当 Backstack 为空时,还应禁用后退按钮。
此示例代码演示如何使用后退按钮实现向后导航行为。 代码对 Button 的 Click 事件作出响应以进行导航。 在 OnNavigatedTo 方法中启用或禁用后退按钮,该方法在导航到新页面时调用。
代码在 MainPage中显示,但是需要将此代码添加到支持后退导航的每个页面。 为了避免重复,可以将导航相关代码放在 App 代码隐藏页的 App.xaml.* 类中。
<!-- MainPage.xaml -->
<Page x:Class="AppName.MainPage">
...
<Button x:Name="BackButton" Click="BackButton_Click"
Style="{StaticResource NavigationBackButtonNormalStyle}"
IsEnabled="{x:Bind Frame.CanGoBack, Mode=OneWay}"
ToolTipService.ToolTip="Back"/>
...
<Page/>
代码隐藏:
// MainPage.xaml.cs
private void BackButton_Click(object sender, RoutedEventArgs e)
{
App.TryGoBack();
}
// App.xaml.cs
//
// Add this method to the App class.
public static bool TryGoBack()
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
rootFrame.GoBack();
return true;
}
return false;
}
// MainPage.h
#include "App.h"
namespace winrt::AppName::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
void MainPage::BackButton_Click(IInspectable const&, RoutedEventArgs const&)
{
App::TryGoBack();
}
};
}
// App.h
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.System.h"
#include "winrt/Windows.UI.Input.h"
#include "winrt/Windows.UI.Xaml.Input.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
struct App : AppT<App>
{
App();
// ...
// Perform back navigation if possible.
static bool TryGoBack()
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
if (rootFrame.CanGoBack())
{
rootFrame.GoBack();
return true;
}
}
return false;
}
};
支持访问密钥
键盘支持是确保应用程序适用于具有不同技能、能力和期望的用户不可或缺的一部分。 我们建议你支持前向和后退导航的快捷键,因为依赖这些键的用户需要这两者。 有关详细信息,请参阅 键盘交互 和 键盘加速器。
前向和后退导航的常见快捷键是 Alt+右箭头键(前进)和 Alt+左箭头键(后退)。 若要支持这些键进行导航,请处理 CoreDispatcher.AcceleratorKeyActivated 事件。 你处理直接在窗口上的事件(而不是页面上的某个元素),这样应用程序在不考虑焦点在哪个元素上的情况下响应快捷键。
将代码添加到 App 类以支持快捷键和向前导航,如下所示。 (假定已添加支持后退按钮的上一个代码。可以在代码示例部分末尾查看所有 App 代码。
// App.xaml.cs
// Add event handler in OnLaunched.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// ...
// rootFrame.NavigationFailed += OnNavigationFailed;
// Add support for accelerator keys.
// Listen to the window directly so the app responds
// to accelerator keys regardless of which element has focus.
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
CoreDispatcher_AcceleratorKeyActivated;
// ...
}
}
// ...
// Add this code after the TryGoBack method added previously.
// Perform forward navigation if possible.
private bool TryGoForward()
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoForward)
{
rootFrame.GoForward();
return true;
}
return false;
}
// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs e)
{
// When Alt+Left are pressed navigate back.
// When Alt+Right are pressed navigate forward.
if (e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown
&& (e.VirtualKey == VirtualKey.Left || e.VirtualKey == VirtualKey.Right)
&& e.KeyStatus.IsMenuKeyDown == true
&& !e.Handled)
{
if (e.VirtualKey == VirtualKey.Left)
{
e.Handled = TryGoBack();
}
else if (e.VirtualKey == VirtualKey.Right)
{
e.Handled = TryGoForward();
}
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// ...
// rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });
// Add support for accelerator keys.
// Listen to the window directly so the app responds
// to accelerator keys regardless of which element has focus.
Window::Current().CoreWindow().Dispatcher().
AcceleratorKeyActivated({ this, &App::CoreDispatcher_AcceleratorKeyActivated });
// ...
}
}
// App.h
struct App : AppT<App>
{
App();
// ...
// Add this code after the TryGoBack method added previously.
private:
// Perform forward navigation if possible.
bool TryGoForward()
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
if (rootFrame.CanGoForward())
{
rootFrame.GoForward();
return true;
}
}
return false;
}
// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher const& /* sender */, AcceleratorKeyEventArgs const& e)
{
// When Alt+Left are pressed navigate back.
// When Alt+Right are pressed navigate forward.
if (e.EventType() == CoreAcceleratorKeyEventType::SystemKeyDown
&& (e.VirtualKey() == Windows::System::VirtualKey::Left || e.VirtualKey() == Windows::System::VirtualKey::Right)
&& e.KeyStatus().IsMenuKeyDown
&& !e.Handled())
{
if (e.VirtualKey() == Windows::System::VirtualKey::Left)
{
e.Handled(TryGoBack());
}
else if (e.VirtualKey() == Windows::System::VirtualKey::Right)
{
e.Handled(TryGoForward());
}
}
}
};
处理系统回退请求
Windows 设备提供了各种方法,系统可以通过各种方式将后退导航请求传递给应用。 一些常见方法是游戏板上的 B 按钮、Windows 键 + Backspace 键快捷方式或平板电脑模式下的系统后退按钮;可用的确切选项取决于设备。
您可以通过为 SystemNavigationManager.BackRequested 事件注册侦听器,来支持来自硬件和软件系统返回键的系统提供的后退请求。
下面是添加到 App 类的代码,以支持系统提供的返回请求。 (假定已添加支持后退按钮的上一个代码。可以在代码示例部分末尾查看所有 App 代码。
// App.xaml.cs
// Add event handler in OnLaunced.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// ...
// Add support for accelerator keys.
// ... (Previously added code.)
// Add support for system back requests.
SystemNavigationManager.GetForCurrentView().BackRequested
+= System_BackRequested;
// ...
}
}
// ...
// Handle system back requests.
private void System_BackRequested(object sender, BackRequestedEventArgs e)
{
if (!e.Handled)
{
e.Handled = TryGoBack();
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// ...
// Add support for accelerator keys.
// ... (Previously added code.)
// Add support for system back requests.
SystemNavigationManager::GetForCurrentView().
BackRequested({ this, &App::System_BackRequested });
// ...
}
}
// App.h
struct App : AppT<App>
{
App();
// ...
private:
// ...
// Handle system back requests.
void System_BackRequested(IInspectable const& /* sender */, BackRequestedEventArgs const& e)
{
if (!e.Handled())
{
e.Handled(TryGoBack());
}
}
};
系统后退行为以实现向后兼容性
以前,UWP 应用使用 SystemNavigationManager.AppViewBackButtonVisibility 显示或隐藏用于向后导航的系统后退按钮。 (此按钮引发 SystemNavigationManager.BackRequested 事件。)此 API 将继续受支持,以确保向后兼容性,但我们不再建议使用公开的 AppViewBackButtonVisibility后退按钮。 相反,您应该提供您自己的应用内后退按钮,如本文所述。
如果您继续使用 AppViewBackButtonVisibility,系统 UI 将在标题栏内呈现系统返回按钮。 (后退按钮的外观和用户交互与以前的版本保持不变。
处理鼠标导航按钮
某些鼠标提供用于向前和后退导航的硬件导航按钮。 您可以通过处理 CoreWindow.PointerPressed 事件,并检查 IsXButton1Pressed(后退)或 IsXButton2Pressed(前进),来支持这些鼠标按钮。
下面是添加到 App 类以支持鼠标按钮导航的代码。 (假定已添加支持后退按钮的上一个代码。可以在代码示例部分末尾查看所有 App 代码。
// App.xaml.cs
// Add event handler in OnLaunced.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// ...
// Add support for system back requests.
// ... (Previously added code.)
// Add support for mouse navigation buttons.
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
// ...
}
}
// ...
// Handle mouse back button.
private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs e)
{
// For this event, e.Handled arrives as 'true'.
if (e.CurrentPoint.Properties.IsXButton1Pressed)
{
e.Handled = !TryGoBack();
}
else if (e.CurrentPoint.Properties.IsXButton2Pressed)
{
e.Handled = !TryGoForward();
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// ...
// Add support for system back requests.
// ... (Previously added code.)
// Add support for mouse navigation buttons.
Window::Current().CoreWindow().
PointerPressed({ this, &App::CoreWindow_PointerPressed });
// ...
}
}
// App.h
struct App : AppT<App>
{
App();
// ...
private:
// ...
// Handle mouse forward and back buttons.
void CoreWindow_PointerPressed(CoreWindow const& /* sender */, PointerEventArgs const& e)
{
// For this event, e.Handled arrives as 'true'.
if (e.CurrentPoint().Properties().IsXButton1Pressed())
{
e.Handled(!TryGoBack());
}
else if (e.CurrentPoint().Properties().IsXButton2Pressed())
{
e.Handled(!TryGoForward());
}
}
};
添加到 App 类的所有代码
// App.xaml.cs
//
// (Add event handlers in OnLaunched override.)
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// ...
// rootFrame.NavigationFailed += OnNavigationFailed;
// Add support for accelerator keys.
// Listen to the window directly so the app responds
// to accelerator keys regardless of which element has focus.
Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
CoreDispatcher_AcceleratorKeyActivated;
// Add support for system back requests.
SystemNavigationManager.GetForCurrentView().BackRequested
+= System_BackRequested;
// Add support for mouse navigation buttons.
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
// ...
}
}
// ...
// (Add these methods to the App class.)
public static bool TryGoBack()
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
rootFrame.GoBack();
return true;
}
return false;
}
// Perform forward navigation if possible.
private bool TryGoForward()
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoForward)
{
rootFrame.GoForward();
return true;
}
return false;
}
// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs e)
{
// When Alt+Left are pressed navigate back.
// When Alt+Right are pressed navigate forward.
if (e.EventType == CoreAcceleratorKeyEventType.SystemKeyDown
&& (e.VirtualKey == VirtualKey.Left || e.VirtualKey == VirtualKey.Right)
&& e.KeyStatus.IsMenuKeyDown == true
&& !e.Handled)
{
if (e.VirtualKey == VirtualKey.Left)
{
e.Handled = TryGoBack();
}
else if (e.VirtualKey == VirtualKey.Right)
{
e.Handled = TryGoForward();
}
}
}
// Handle system back requests.
private void System_BackRequested(object sender, BackRequestedEventArgs e)
{
if (!e.Handled)
{
e.Handled = TryGoBack();
}
}
// Handle mouse back button.
private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs e)
{
// For this event, e.Handled arrives as 'true'.
if (e.CurrentPoint.Properties.IsXButton1Pressed)
{
e.Handled = !TryGoBack();
}
else if (e.CurrentPoint.Properties.IsXButton2Pressed)
{
e.Handled = !TryGoForward();
}
}
// App.cpp
void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
// ...
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == nullptr)
{
// ...
// rootFrame.NavigationFailed({ this, &App::OnNavigationFailed });
// Add support for accelerator keys.
// Listen to the window directly so the app responds
// to accelerator keys regardless of which element has focus.
Window::Current().CoreWindow().Dispatcher().
AcceleratorKeyActivated({ this, &App::CoreDispatcher_AcceleratorKeyActivated });
// Add support for system back requests.
SystemNavigationManager::GetForCurrentView().
BackRequested({ this, &App::System_BackRequested });
// Add support for mouse navigation buttons.
Window::Current().CoreWindow().
PointerPressed({ this, &App::CoreWindow_PointerPressed });
// ...
}
}
// App.h
#include "winrt/Windows.UI.Core.h"
#include "winrt/Windows.System.h"
#include "winrt/Windows.UI.Input.h"
#include "winrt/Windows.UI.Xaml.Input.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
struct App : AppT<App>
{
App();
// ...
// Perform back navigation if possible.
static bool TryGoBack()
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
if (rootFrame.CanGoBack())
{
rootFrame.GoBack();
return true;
}
}
return false;
}
private:
// Perform forward navigation if possible.
bool TryGoForward()
{
Frame rootFrame{ nullptr };
auto content = Window::Current().Content();
if (content)
{
rootFrame = content.try_as<Frame>();
if (rootFrame.CanGoForward())
{
rootFrame.GoForward();
return true;
}
}
return false;
}
// Invoked on every keystroke, including system keys such as Alt key combinations.
// Used to detect keyboard navigation between pages even when the page itself
// doesn't have focus.
void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher const& /* sender */, AcceleratorKeyEventArgs const& e)
{
// When Alt+Left are pressed navigate back.
// When Alt+Right are pressed navigate forward.
if (e.EventType() == CoreAcceleratorKeyEventType::SystemKeyDown
&& (e.VirtualKey() == Windows::System::VirtualKey::Left || e.VirtualKey() == Windows::System::VirtualKey::Right)
&& e.KeyStatus().IsMenuKeyDown
&& !e.Handled())
{
if (e.VirtualKey() == Windows::System::VirtualKey::Left)
{
e.Handled(TryGoBack());
}
else if (e.VirtualKey() == Windows::System::VirtualKey::Right)
{
e.Handled(TryGoForward());
}
}
}
// Handle system back requests.
void System_BackRequested(IInspectable const& /* sender */, BackRequestedEventArgs const& e)
{
if (!e.Handled())
{
e.Handled(TryGoBack());
}
}
// Handle mouse forward and back buttons.
void CoreWindow_PointerPressed(CoreWindow const& /* sender */, PointerEventArgs const& e)
{
// For this event, e.Handled arrives as 'true'.
if (e.CurrentPoint().Properties().IsXButton1Pressed())
{
e.Handled(!TryGoBack());
}
else if (e.CurrentPoint().Properties().IsXButton2Pressed())
{
e.Handled(!TryGoForward());
}
}
};
继续
当用户切换到另一个应用并返回到你的应用时,我们建议返回到导航历史记录中的最后一页。