shell 毛伊岛:如何防止导航离开包含未保存数据的页面?

ttp71kqs  于 2023-03-13  发布在  Shell
关注(0)|答案(1)|浏览(122)

我用Shell导航实现了一个Maui应用程序,有一个页面可能有未保存的数据,当用户导航离开该页面时,我想问他们想做什么(导航离开并丢弃数据或留在页面上-或其他类似的选择)。
环境为VS 2022,Maui v7.0。
我看到过一些文章处理后退按钮,但是还有其他方法可以离开页面,比如页面上的控件或者使用弹出菜单。
我希望解决方案在任何情况下都能工作,而不管导航是如何启动的。我该如何做到这一点?

jchrr9hc

jchrr9hc1#

最后我使用了Page.onNavigating()事件,因为每次从我的页面进行导航时都会触发该事件。
但有一些警告:事件处理程序需要以一种巧妙的方式被注册和取消注册,以防止多次注册。
在事件处理程序中,我显示了一个用户对话框。在用户交互期间,导航必须暂停,并根据用户的决定执行或取消。在事件参数上有一个(截至本文撰写时)未记录的方法,称为GetDeferral(),我需要使用它。
我是这样实现的。

事件处理程序注册

我试着在构造函数中注册,在析构函数中注销,但是没有用。我使用依赖注入,页面被注册为 transient 。当导航离开页面时,析构函数还没有被调用,第二次查看该页将第二次注册该事件处理程序。将页注册更改为单一示例会导致页控件生存期出现问题。最终在OnAppearing/OnDisappearing方法:
在我的页面xaml.cs中:

public partial class TablePartyPage : ContentPage, IDisposable
{
    private MyViewModel _vm;
    [...]
    
    protected override void OnAppearing()
    {
        base.OnAppearing();
        Shell.Current.Navigating += OnNavigating;
    }

    protected override void OnDisappearing()
    {
        Shell.Current.Navigating -= OnNavigating;
        base.OnDisappearing();
    }
    
    private async void OnNavigating(object sender, ShellNavigatingEventArgs args)
    {
        // I define constants for page routes and register them in AppShell,
        // here I use those routes to allow certain navigation targets
        if (args.Target.Location.OriginalString.EndsWith(AppShell.MyPageRoute)
            || args.Target.Location.OriginalString.EndsWith(AppShell.MyChildPageRoute))
        {   // Navigating to this page or one of its children - allow this navigation
            return;
        }
        else
        {   // Navigating away from this page
            if (!_vm.HasUnsavedChanges)
                return; // No unsaved changes - allow navigation

            // Pause navigation till the user makes a decision
            var deferral = args.GetDeferral();

            const string STAY = "Stay on this page";
            const string DISCARD = "Discard changes";
            switch (await DisplayActionSheet(
                "There are unsaved changes on this page", null, null, STAY, DISCARD))
            {
                case STAY:
                default:
                    // Do not leave this page, cancel navigation
                    args.Cancel();
                    break;

                case DISCARD:
                    _vm.DiscardChanges();
                    break;
            }
            
            // Un-pause navigation
            deferral.Complete();
        }
    }
}

相关问题