清除 Xamarin Forms 模态栈

5
我有一个使用NavigationPage进行正常屏幕导航的Xamarin.Forms应用程序。从其中一个屏幕(Stay Detail)开始,我需要显示一系列4个顺序模态页面(类似于向导),以收集完成与Stay Detail相关的过程所需的数据。流程中的每个页面都有一个“取消”按钮,允许用户取消向导并返回到Stay Detail。以下是一般的流程:
            modal1 -> modal2 -> modal3 -> modal4
           /                                    \
 StayDetail                                      StayDetail

从StayDetail启动modal1很容易,只需使用PushModalAsync,然后使用PushModalAsync / PopModalAsync在各个模态页面之间进行导航。但是,我无法找到一种干净的方式从第2个或更高级别的模态中退出模态堆栈。最好的方法是什么?


我今天遇到了同样的问题。在解决问题的过程中,我想出了答案。 - Dbl
对于不想返回到最开始而是返回到之前模态页面的任何人,我在这个类似的问题中提供了答案:https://stackoverflow.com/a/55613281/101087 - NineBerry
1个回答

0
这个解决方案可能在您的情况下看起来过于复杂,但我正在使用它来在随机情况下在模态操作之间进行通信以解决依赖关系(没有帐户存在,缺少ID,同时数据已被删除等),而不会失去类型安全性。
一种思考向导/模态序列的方法是,下一页取决于前一页,并且大多数情况下,您将想要使用子模态的结果进行工作。
我希望这能有所帮助。
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; }
}

1
我猜这就是德国人过度设计事物的刻板印象来源吧... - Dbl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接