【问题标题】:Clear Xamarin Forms Modal Stack清除 Xamarin 表单模式堆栈
【发布时间】:2016-08-21 21:10:32
【问题描述】:

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

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

从 StayDetail 执行 PushModalAsync 以启动 modal1,然后 PushModalAsync/PopModalAsync 在各个模态页面之间切换非常简单。但是,我无法找到一种干净的方式从第二个或更高模式退出模式堆栈。最好的方法是什么?

【问题讨论】:

  • 我今天也遇到了同样的问题。研究我想出的答案
  • 对于那些不想一路返回但又想回到上一个模态页面的人,我在这个类似的问题中提供了答案:stackoverflow.com/a/55613281/101087

标签: c# xamarin.forms


【解决方案1】:

对于您的情况,此解决方案可能看起来过于复杂,但它是我用来在模态操作之间进行通信以随机解决依赖关系(不存在帐户、缺少 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; }
}

【讨论】:

  • 我想这就是德国人过度设计事物的刻板印象的来源......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
相关资源
最近更新 更多