清除Xamarin形式模态堆栈 [英] Clear Xamarin Forms Modal Stack

查看:113
本文介绍了清除Xamarin形式模态堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Xamarin.Forms应用程序,该应用程序使用NavigationPage进行常规屏幕导航.从一个屏幕(Stay Detail)中,我需要显示一系列4个连续的模式页面(如向导),这些页面收集数据以完成与Stay Detail相关的过程.该过程中的每个页面都有一个取消"按钮,该按钮应允许用户取消向导并返回到停留详细信息".这是一般流程:

I have a Xamarin.Forms application that uses a NavigationPage for normal screen navigation. From one of the screens (Stay Detail), I need to display a series of 4 sequential modal pages (like a wizard) that collects data to complete a process related to Stay Detail. Each page in the process has a "Cancel" button that should allow the user to cancel out of the wizard and return to Stay Detail. Here is the general flow:

            modal1 -> modal2 -> modal3 -> modal4
           /                                    \
 StayDetail                                      StayDetail

从StayDetail进行PushModalAsync以启动modal1,然后在各个模态页面之间进行PushModalAsync/PopModalAsync都很容易.但是,我想不出一种从第二个模态或更高版本退出模态堆栈的干净方法.最好的方法是什么?

It's easy enough to do a PushModalAsync from StayDetail to launch modal1, then PushModalAsync/PopModalAsync to go between the individual modal pages. However, I can't figure out a clean way to exit out of the modal stack from the 2nd modal or later. What's the best way to do that?

推荐答案

对于您的情况,此解决方案可能看起来过于复杂,但这就是我用来在模态操作之间进行通信以解决依赖关系的原因(没有帐户,缺少ID) ,同时删除数据等),而不会丢失类型安全性.

This solution will probably look overly complicated for your case, but it's what i'm using to communicate between modal actions to resolve dependencies (no account present, id missing, data deleted in the meantime etc) at random without losing type safety.

思考向导/模态系列的一种方法是,下一页取决于上一页,并且大多数情况下,您将希望使用子模态的结果.

One way to think about wizards / a modal series is, that the next page depends on the previous and that mostly you will want to work with the result of your child modal.

我希望这会有所帮助:

public static class ModalManager
{
    public static bool TryRespondModal<TData>(this IModalResponse<TData> source, TData data, bool autoPop = true, bool animate = false)
    {
        if (Application.Current.MainPage.Navigation.ModalStack.Count <= 0)
            return false;

        source.ModalRequestComplete.SetResult(data);

        if (autoPop)
            Application.Current.MainPage.Navigation.PopModalAsync(animate);

        return true;
    }

    public static Task<TData> GetResponseAsync<TData>(this IModalResponse<TData> source)
    {
        source.ModalRequestComplete = new TaskCompletionSource<TData>();
        return source.ModalRequestComplete.Task;
    }
}

public enum WizardState
{
    Indeterminate = 0,
    Complete = 1,
    Canceled = 2
}

public class WizardModel
{
    public WizardState State { get; set; }

    public List<string> Page1Values { get; set; } = new List<string>();
    public List<string> Page2Values { get; set; } = new List<string>();
    public List<string> Page3Values { get; set; } = new List<string>();
}

public abstract class WizardPage : IModalResponse<WizardModel>
{
    public WizardModel Model { get; set; }

    public ICommand NextCommand { get; set; }

    public ICommand PreviousCommand { get; set; }

    public ICommand CancelCommand { get; set; }

    protected WizardPage(WizardModel model)
    {
        Model = model;
        NextCommand = new Command(NextButtonPressed);
        PreviousCommand = new Command(PreviousButtonPressed);
        CancelCommand = new Command(PreviousButtonPressed);
    }

    protected abstract IModalResponse<WizardModel> GetNextPage();

    protected virtual void CancelButtonPressed()
    {
        Model.State = WizardState.Canceled;
        this.TryRespondModal(Model);
    }

    protected virtual void PreviousButtonPressed()
    {
        // you're dropping down on the level of dependent windows here so you can tell your previous modal window the result of the current response
        this.TryRespondModal(Model);
    }

    protected virtual async void NextButtonPressed()
    {
        var np = GetNextPage();
        if (Model.State == WizardState.Complete || np == null || (await np?.GetResponseAsync()).State == WizardState.Complete)
            PersistWizardPage();

        // all following modal windows must have run through - so you persist whatever your page has done, unless you do that on the last page anyway. and then tell the previous
        // modal window that you're done
        this.TryRespondModal(Model);
    }

    protected virtual void PersistWizardPage()
    {
        // virtual because i'm lazy
        throw new NotImplementedException();
    }

    public TaskCompletionSource<WizardModel> ModalRequestComplete { get; set; }
}

public class Page1 : WizardPage
{

    public Page1(WizardModel model) : base(model)
    {
    }

    protected override IModalResponse<WizardModel> GetNextPage()
    {
        return new Page2(Model);
    }
}

public class Page2 : WizardPage
{
    public Page2(WizardModel model) : base(model)
    {
    }

    protected override IModalResponse<WizardModel> GetNextPage()
    {
        return new Page3(Model);
    }
}

public class Page3 : WizardPage
{
    public Page3(WizardModel model) : base(model)
    {
    }

    protected override IModalResponse<WizardModel> GetNextPage()
    {
        return null;
    }

    protected override void NextButtonPressed()
    {
        this.Model.State = WizardState.Complete;
        base.NextButtonPressed();
    }
}

public interface IModalResponse<TResponseType>
{
    TaskCompletionSource<TResponseType> ModalRequestComplete { get; set; }
}

这篇关于清除Xamarin形式模态堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆