Frame.GoBack()成功点击UI按钮,Windows软件后退按钮回调失败

时间:2018-03-06 02:08:16

标签: c# uwp navigation windows-10-universal

我有一个语言学习应用程序,其中包含以下基本页面导航结构:

  1. 开始 - 应用标题屏幕
  2. 语言 - 语言列表
  3. 课程 - 所选语言的课程列表
  4. 活动 - 包含所选课程的活动的页面
  5. 前三页各有一个按钮,可以通过类似于:

    的调用导航到下一页
    private void ButtonClick(object sender, RoutedEventArgs e) => Frame.Navigate(typeof(SomePage));
    

    在“活动”页面上,用户按下按钮提交最后一个正确答案后,应用程序会像这样导航:

    private async void SubmitAnswer_Click(object sender, RoutedEventArgs e)
    {
        ...
    
        if (answerCorrect && allActivitiesComplete)
        {
            Frame.GoBack();
            return;
        }
    
        ...
    }
    

    有效;我回到了课程页面。如果我将鼠标悬停在使用IntelliSense的Frame上,我会看到BackStack属性的计数为3,前一页每个都有一个。

    但是,我也想显示软件后退按钮。为此,我有以下代码:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        ...
        var nav = SystemNavigationManager.GetForCurrentView();
        nav.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
        ...
    }
    

    很好,现在按钮显示在桌面模式的左上角。但按下它什么都不做。所以我用以下内容更新:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        ...
        var nav = SystemNavigationManager.GetForCurrentView();
        nav.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
        nav.BackRequested += (x, y) =>
        {
            Frame.GoBack();
        };
        ...
    }
    

    失败

    Error HRESULT E_FAIL has been returned from a call to a COM component.
    

    Frame.BackStack显示0Frame.CanGoBackfalse。为什么此代码流与按钮代码流不一致?

2 个答案:

答案 0 :(得分:1)

理想情况下,您应该全局连接BackRequested事件,而不是在特定页面的范围内。这是因为如果添加事件处理程序OnNavigatedTo,则每次导航页面时都会添加另一个事件处理程序。这意味着单击后退按钮将多次导航。此外,保留所有页面附加处理程序在内存中,这是严重的内存泄漏。至少应该从使用lamda切换到事件处理程序方法,并在OnNavigatedFrom中取消订阅。

要正确实现应用标题栏后退按钮,您应该这样做:

  1. 观察Frame Navigated方法,根据CanGoBack属性
  2. 显示/隐藏后退按钮
  3. BackRequested处理程序中检查CanGoBack以确保可以导航
  4. 空白UWP应用的实施示例如下:

    将以下方法添加到App.xaml.cs

    private void SetupAppBarBackButton()
    {
        _rootFrame.Navigated += RootFrame_Navigated;
        SystemNavigationManager.GetForCurrentView().BackRequested += App_BackRequested;
    }
    
    private void App_BackRequested(object sender, BackRequestedEventArgs e)
    {
        if (_rootFrame.CanGoBack)
        {
            _rootFrame.GoBack();
        }
    }
    
    private void RootFrame_Navigated(object sender, NavigationEventArgs e)
    {
        SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
            _rootFrame.CanGoBack
               ? AppViewBackButtonVisibility.Visible
               : AppViewBackButtonVisibility.Collapsed;
    }
    

    还要添加私人_rootFrame字段:

    private Frame _rootFrame;
    

    最后更新OnLaunched方法以存储根框架并设置后退按钮:

    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)
        {
            ...
    
            // Place the frame in the current Window
            Window.Current.Content = rootFrame;
    
            _rootFrame = rootFrame;
            SetupAppBarBackButton();
        }
        ...
    }
    

    请注意,如果您正在其他地方创建根框架(例如其他激活路径),您还需要存储框架并在那里调用SetupAppBarBackButton方法。

答案 1 :(得分:0)

试试这个:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    ...

    Windows.UI.Core.SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += (s,a) =>
    {

        if (Frame.CanGoBack)
        {
            Frame.GoBack();
            a.Handled = true;
        }
    }
    ...
}