簡體   English   中英

Xamarin從INavigationService形成MVVM清除導航堆棧

[英]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中做到這一點,但在常規表單中你有幾個選項來實現你想要的:

  1. 如果您需要返回登錄或注冊頁面,則應使用

     await Navigation.PushModalAsync(new YourMasterDetailPage()); 

然后你可以popmodal回到他們但是在這種情況下硬件按鈕仍然會帶你登錄。 導航到主 - 詳細信息頁面后,可以使用方法2的一部分清除堆棧但要小心 - 如果頁面是根目錄和當前顯示的頁面,則無法從堆棧中刪除頁面,因此您只需在清除后定期導航堆棧登錄頁面不顯示。 我不建議使用該選項,因為“模態視圖通常是臨時的,只能在屏幕上播放足夠長的時間以便用戶完成任務。”

http://blog.adamkemp.com/2014/09/navigation-in-xamarinforms_2.html

  1. 如果您不需要返回,可以使用以下清除導航堆棧,它也將刪除后退按鈕

     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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM