![](/img/trans.png)
[英]Xamarin Forms MVVM Clear Navigation Stack from INavigationService
[英]Clear Xamarin Forms Modal Stack
我有一个 Xamarin.Forms 应用程序,它使用 NavigationPage 进行普通屏幕导航。 在其中一个屏幕(Stay Detail)中,我需要显示一系列 4 个连续模式页面(如向导),这些页面收集数据以完成与 Stay Detail 相关的流程。 流程中的每个页面都有一个“取消”按钮,该按钮应允许用户取消向导并返回到“保持详细信息”。 这是一般流程:
modal1 -> modal2 -> modal3 -> modal4
/ \
StayDetail StayDetail
从 StayDetail 执行 PushModalAsync 以启动 modal1,然后在各个模式页面之间执行 PushModalAsync/PopModalAsync 非常容易。 但是,我想不出一种干净的方法从第二个模态或更高版本退出模态堆栈。 这样做的最佳方法是什么?
每次用户导航到下一个模态时,您不能只执行以下操作吗?
await Navigation.PushModalAsync(new modal2()); //Send user to new modal2 pages
await Navigation.PopModalAsync(); //Pop modal1 page
然后当他们点击取消按钮时,你会再做一次PopModalAsync()
并返回到StayDetail
页面,因为你已经弹出了下面的所有模态。
如果他们在获得modal2之后需要一种方法回到modal1,你可以简单地传递modal1需要的任何数据,同时创建一个新的页面:
Modal1Data modalData = new Modal1Data();
await Navigation.PushModalAsync(new modal1(modalData)); //Push old modal with previously entered data
await Navigation.PopModalAsync(); //Pop modal2 page
您甚至可以在导航回modal1之前保存已从modal2输入的数据,这样当用户返回到modal2时,他们的所有信息仍会显示在屏幕上。
对于你的情况,这个解决方案可能看起来过于复杂,但是我正在使用模式操作之间进行通信以解决依赖关系(没有帐户存在,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; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.