Windows Phone后退按钮未被处理

时间:2014-12-06 16:15:45

标签: c# windows-phone-8.1 prism win-universal-app

我已经使用HardwareButtons.BackPressed事件注册了一个处理程序,执行了一些逻辑,然后在args中将handle属性设置为true(如果适用)。处理程序运行时没有任何问题,并且Handled属性已设置。手机仍会在应用程序外导航回来。我误解了如何使用这个活动吗?

public sealed partial class FirstRunPage : VisualStateAwarePage
{
    public FirstRunPage()
    {
        this.InitializeComponent();
#if WINDOWS_PHONE_APP
        HardwareButtons.BackPressed += (sender, args) =>
            {
                bool isHandled = false;
                Action handledCallback = () => isHandled = true;
                var state = new Dictionary<string, object> { { "Callback", handledCallback } };
                ((INavigationAware)this.DataContext).OnNavigatedTo("Back", NavigationMode.Back, state);
                args.Handled = isHandled;
            };
#endif
    }

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

查看模型。

    public override void OnNavigatedTo(object navigationParameter, NavigationMode navigationMode, Dictionary<string, object> viewModelState)
    {
        if (navigationParameter == null || !navigationParameter.ToString().Equals("Back"))
        {
            return;
        }

        if (!viewModelState.ContainsKey("Callback"))
        {
            return;
        }

        var callback = (Action)viewModelState["Callback"];

        // If the user is new, then we set it to false and invoke our callback.
        if (this.IsNewUser)
        {
            this.IsNewUser = false;
            callback();
        }
        else
        {
            return;
        }
    }

更新

我修改了我的FirstRunPage以按照@Martin的建议订阅和取消订阅,但它仍然会关闭该应用。

public sealed partial class FirstRunPage : VisualStateAwarePage
{
    public FirstRunPage()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
#if WINDOWS_PHONE_APP
        HardwareButtons.BackPressed += HardwareBack_OnPressed;
#endif
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        base.OnNavigatedFrom(e);
#if WINDOWS_PHONE_APP
        HardwareButtons.BackPressed -= HardwareBack_OnPressed;
#endif
    }

    private void HardwareBack_OnPressed(object sender, BackPressedEventArgs e)
    {
        Action handledCallback = () => e.Handled = true;
        var state = new Dictionary<string, object> { { "Callback", handledCallback } };

        ((INavigationAware)this.DataContext).OnNavigatedTo("Back", NavigationMode.Back, state);
    }        
}

2 个答案:

答案 0 :(得分:3)

在@yasen的帮助下,我能够解决这个问题。问题源于Prism库让您的App.xaml.cs继承自MvvmAppbase,它拦截BackPressed事件。

为了解决这个问题,我重写了MvvmAppBase OnHardwareButtonsBackPressed并添加了一些逻辑来处理它。 我的视图模型和视图都实现了一个名为INavigateBackwards的新接口,它们的使用方式如下:

查看模型

    public bool CanNavigateBack()
    {
        // If the new user is true, then we can't navigate backwards.
        // There isn't any navigation stack, so the app will die.
        bool canNavigate = !this.IsNewUser;

        // Disable the new user mode.
        this.IsNewUser = false;

        // Return so that the view can return to it's sign-in state.
        return canNavigate;
    }

视图

public sealed partial class FirstRunPage : VisualStateAwarePage, INavigateBackwards
{
    private INavigateBackwards ViewModel
    {
        get
        {
            return (INavigateBackwards)this.DataContext;
        }
    }

    public FirstRunPage()
    {
        this.InitializeComponent();
    }

    public bool CanNavigateBack()
    {
        return ViewModel.CanNavigateBack();
    }
}

然后在MvvmAppBase子类中,我确定是否需要处理导航。

MvvmAppBase孩子

    protected override void OnHardwareButtonsBackPressed(object sender, BackPressedEventArgs e)
    {
        var page = (Page)((Frame)Window.Current.Content).Content;
        if (page is INavigateBackwards)
        {
            var navigatingPage = (INavigateBackwards)page;
            if (!navigatingPage.CanNavigateBack())
            {
                e.Handled = true;
                return;
            }
        }

        base.OnHardwareButtonsBackPressed(sender, e);
    }

这允许我的单个视图具有多个状态,用户可以从一个状态导航回到上一个状态而无需导航到全新视图。

答案 1 :(得分:0)

您的应用程序关闭的原因是同一个处理程序被调用的次数不止一次。第一个处理程序将Handled属性设置为true,但对同一事件触发的任何其他后续调用都会将其设置回false

为了说明一下,试试这个:

public sealed partial class FirstRunPage : VisualStateAwarePage
{
    public FirstRunPage()
    {
       // ...
       InitializeComponent();
       HardwareButtons.BackPressed += HardwareButtons_BackPressed;   
       HardwareButtons.BackPressed += HardwareButtons_BackPressed; 
    }

    void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
    {
        bool isHandled = false;
        Action handledCallback = () => isHandled = true;
        var state = new Dictionary<string, object> { { "Callback", handledCallback } };
        ((INavigationAware)this.DataContext).OnNavigatedTo("Back", NavigationMode.Back, state);
        args.Handled = isHandled;
    };
}

并将断点设置为处理程序代码的最后一行。

要避免这种情况,请使用OnNavigatedTo的{​​{1}}方法分配处理程序,并在FirstRunPage中取消注册处理程序。

OnNavigatedFrom