这篇文章主要总结一下Windows 10 UWP开发中关于页面导航及后退按钮的一些省时省力的技巧。

页面导航


导航到另一个页面,用的是Frame的Navigate方法,parameter参数是可选的:

public System.Boolean Navigate(Type sourcePageType, System.Object parameter);

比如你的目标页面是TargetPage.xaml,通常类型就是TargetPage,所以就可以这样搞:

Frame.Navigate(typeof(TargetPage), ParametersObject);

在目标页面接受参数,用的是OnNavigatedTo,然后把e.Parameter转换成你的参数类型,再自己撸一下就好,比如:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var line = e.Parameter as MetroLine;
    var vm = DataContext as LineDetailViewModel;
    vm?.InitData(line);
    base.OnNavigatedTo(e);
}

后退


导航完了默认是不能后退的,这和Windows Phone 8.x的Silverlight Runtime很不一样,原先按手机的硬件后退按钮就可以自动后退。现在我们必须写代码了。当然,如果你做过Windows Phone 8.1 Runtime的开发,其实UWP里是很类似的。

要后退,用的是:

Frame.GoBack()

但是最好得判断一下能不能后退再后退:

if (Frame.CanGoBack)
{
    Frame.GoBack();
}

在UWP的标题栏上爆一个后退按钮:

SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible

如果你希望这个后退按钮能根据当前页面是否允许后退而自动显示或隐藏:

SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
    Frame.CanGoBack ?
    AppViewBackButtonVisibility.Visible :
    AppViewBackButtonVisibility.Collapsed;

后退按钮的事件是:

SystemNavigationManager.GetForCurrentView().BackRequested

然后你需要在这个事件里写:

if (Frame.CanGoBack)
{
    Frame.GoBack();
}

自动处理后退按钮的逻辑


每个页面都像上面这么写非常蛋疼,而且代码很冗余。有个小技巧,也是网上看到的借鉴别人的:

在你的App.xaml.cs里面,有个

protected override void OnLaunched(LaunchActivatedEventArgs e)

把这个方法改成这样:

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;
        rootFrame.Navigated += OnNavigated; // <---- 这里

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            //TODO: Load state from previously suspended application
        }

        // Place the frame in the current Window
        Window.Current.Content = rootFrame;

// 还有这里 // Register a handler for BackRequested events and set the // visibility of the Back button SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = rootFrame.CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed; } 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(MainPage), e.Arguments); } // Ensure the current window is active Window.Current.Activate(); }

OnNavigated事件里处理一下后退按钮是否显示:

private void OnNavigated(object sender, NavigationEventArgs e)
{
    // Each time a navigation event occurs, update the Back button's visibility
    SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
        ((Frame)sender).CanGoBack ?
        AppViewBackButtonVisibility.Visible :
        AppViewBackButtonVisibility.Collapsed;
}

按下后退按钮(设备硬件按钮或是UWP标题栏上的软件按钮都行):

private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
    Frame rootFrame = Window.Current.Content as Frame;

    if (rootFrame != null && rootFrame.CanGoBack)
    {
        e.Handled = true;
        rootFrame.GoBack();
    }
}

在手机上按后退按钮彻底退出应用而不是挂起


多年前写过一篇:

Windows Phone Runtime 8.1 按返回键彻底关闭App

把上面的代码和这篇的代码撸一块去就是:

private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
    Frame rootFrame = Window.Current.Content as Frame;

    if (rootFrame != null)
    {
        if (rootFrame.CanGoBack)
        {
            e.Handled = true;
            rootFrame.GoBack();
        }
        else
        {
            Application.Current.Exit();
        }
    }
}

但是有可能被不明真相却以为自己了解UWP的用户说你的应用是Silverlight的,因为按后退之后不见了,然后给你打1星,不要问我怎么知道的……

后退时候保持前一个页面的状态


如果你前一个页面是个很长的列表,点某一项前进到详细页面,再返回的话,默认情况是会还原列表页面的初始状态,也就是用户会发现列表又滚到最上面了,要重新滚,可能会被打1星,所以要稍微撸一下:

在前一个页面的构造函数里加一个NavigationCacheMode进去

public MainPage()
{
    InitializeComponent();
    NavigationCacheMode = NavigationCacheMode.Enabled;
}

这样后退的时候就能保持前一个页面的状态了。