[英]Xamarin Forms using MVVM Light - Remove Navigation pages from stack
[英]Xamarin Forms MVVM Clear Navigation Stack from INavigationService
我正在處理的項目包含以下結構:
啟動應用程序后,用戶會看到歡迎頁面。 此時用戶有兩種選擇。 他們可以登錄或注冊。 如果登錄== true; 然后轉到主詳細頁面。 或者在注冊時,如果注冊==成功,則轉到登錄頁面並按照相同的過程進入主詳細信息頁面。
-> Login Page ||
Welcome Page >> ================== || => MasterDetailPage
-> Register Page -> Login page ||
我正在使用MVVM Light通過INavigationService處理我的導航堆棧,因為我的UI和業務邏輯通過MVVM分離。 一切都很好,除了我需要重置導航堆棧,以便用戶在上面顯示的“MasterDetailPage”之前無法訪問任何頁面。 現在,用戶可以使用Android上的硬件返回按鈕或從iOS上的左邊緣輕掃,返回登錄或注冊或之前的任何頁面。 另外,頂部導航欄上還有一個導航后退按鈕。
我的App.cs看起來像這樣
public App()
{
var nav = RegisterNavigationService();
SimpleIoc.Default.Register<INavigationService>(() => nav);
InitializeComponent();
var initialPage = new NavigationPage(new WelcomePage());
nav.Initialize(initialPage);
MainPage = initialPage;
}
private NavigationService RegisterNavigationService()
{
var nav = new NavigationService();
nav.Configure(Locator.LoginForm, typeof(LoginForm));
nav.Configure(Locator.RegisterSuccessPage, typeof(RegisterSuccessPage));
nav.Configure(Locator.RegistrationForm, typeof(RegistrationForm));
nav.Configure(Locator.WelcomePage, typeof(WelcomePage));
nav.Configure(Locator.MasterMainPage, typeof(MasterMainPage));
return nav;
}
在我的視圖模型中,我處理這樣的導航命令:
public class LoginFormViewModel : BaseViewModel
{
private readonly INavigationService _navigationService;
public Command NavigateToMainPage { get; }
public LoginFormViewModel(INavigationService navigationService)
{
_navigationService = navigationService ?? throw new ArgumentNullException("navigationService");
NavigateToMainPage = new Command(() => NavigateToMainApp());
}
private void NavigateToMainApp()
{
_navigationService.NavigateTo(Locator.MasterMainPage);
}
}
最后,我的NavigationService.cs看起來像這樣......我幾乎沒碰過這部分代碼......我唯一嘗試的是'ClearNavigationStack'方法,但這是一個失敗。
public class NavigationService : INavigationService, INavigationServiceExtensions
{
private Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
private NavigationPage _navigation;
public string CurrentPageKey
{
get
{
lock (_pagesByKey)
{
if (_navigation.CurrentPage == null)
{
return null;
}
var pageType = _navigation.CurrentPage.GetType();
return _pagesByKey.ContainsValue(pageType)
? _pagesByKey.First(p => p.Value == pageType).Key
: null;
}
}
}
public void GoBack()
{
_navigation.PopAsync();
}
public void NavigateTo(string pageKey)
{
NavigateTo(pageKey, null);
}
public void NavigateTo(string pageKey, object parameter)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
ConstructorInfo constructor;
object[] parameters;
var type = _pagesByKey[pageKey];
if (parameter == null)
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(c => !c.GetParameters().Any());
parameters = new object[] { };
}
else
{
constructor = type.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(
c =>
{
var p = c.GetParameters();
return p.Count() == 1
&& p[0].ParameterType == parameter.GetType();
});
parameters = new[] { parameter };
}
if (constructor == null)
{
throw new InvalidOperationException("No suitable constructor found for page " + pageKey);
}
var page = constructor.Invoke(parameters) as Page;
_navigation.PushAsync(page);
}
else
{
throw new ArgumentException(
string.Format("No such page: {0}. Did you forget to call NavigationService.Configure?", pageKey), "pageKey");
}
}
}
public void Configure(string pageKey, Type pageType)
{
lock (_pagesByKey)
{
if (_pagesByKey.ContainsKey(pageKey))
{
_pagesByKey[pageKey] = pageType;
}
else
{
_pagesByKey.Add(pageKey, pageType);
}
}
}
public void ClearNavigationStack()
{
lock (_pagesByKey)
{
foreach (var pageKey in _pagesByKey.Keys)
{
_pagesByKey.Remove(pageKey);
}
}
}
public void Initialize(NavigationPage navigation)
{
_navigation = navigation;
}
}
我從以下git repo中獲取了這一點: https : //github.com/mallibone/MvvmLightNavigation.XamarinForms
遵循本教程: https : //mallibone.com/post/xamarin.forms-navigation-with-mvvm-light
注意:它是PCL。
任何建議都是受歡迎的,因為我在過去的兩天里一直在討論這個問題。
編輯:剛才,我已經設法通過將我的MainPage設置為這樣來“隱藏”導航堆棧
App.Current.MainPage = new MasterMainPage();
但它看起來像一個代碼味道,看起來像一個可怕的黑客。 此外,我不太確定它是否“違反”我所遵循的概念......我猜這個導航堆棧永遠不會消失,因為我將在主細節頁面內做其他導航堆棧。
從您的圖片中我看到您在導航頁面中有Master / Detaied頁面。 Xamarin不建議這樣做。 我不知道你將如何在MVVM Light中做到這一點,但在常規表單中你有幾個選項來實現你想要的:
如果您需要返回登錄或注冊頁面,則應使用
await Navigation.PushModalAsync(new YourMasterDetailPage());
然后你可以popmodal回到他們但是在這種情況下硬件按鈕仍然會帶你登錄。 導航到主 - 詳細信息頁面后,可以使用方法2的一部分清除堆棧但要小心 - 如果頁面是根目錄和當前顯示的頁面,則無法從堆棧中刪除頁面,因此您只需在清除后定期導航堆棧登錄頁面不顯示。 我不建議使用該選項,因為“模態視圖通常是臨時的,只能在屏幕上播放足夠長的時間以便用戶完成任務。”
http://blog.adamkemp.com/2014/09/navigation-in-xamarinforms_2.html
如果您不需要返回,可以使用以下清除導航堆棧,它也將刪除后退按鈕
await Navigation.PushAsync(new YourMasterPage()); var pages = Navigation.NavigationStack.ToList(); foreach (var page in pages) { if (page.GetType() != typeof(YourMasterPage)) Navigation.RemovePage(page); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.