Xamarin从INAVigationService

时间:2017-06-12 17:41:39

标签: c# xamarin mvvm xamarin.forms mvvm-light

我正在处理的项目包含以下结构:

启动应用后,用户会看到欢迎页面。此时用户有两种选择。他们可以登录或注册。如果登录== true;然后转到主详细页面。或者在注册时,如果注册==成功,则转到登录页面并按照相同的流程进入主详细信息页面。

                -> Login Page                  ||
Welcome Page >> ==================             || => MasterDetailPage
                -> Register Page -> Login page ||

我正在使用MVVM Light通过INavigationService处理我的导航堆栈,因为我的UI和业务逻辑通过MVVM分离。一切都很好,除了我需要重置导航堆栈,这样用户将无法在" MasterDetailPage"之前访问任何页面。如上所示。现在,用户可以使用Android上的硬件返回按钮或从iOS上的左边缘轻扫,返回登录或注册或之前的任何页面。另外,顶部导航栏上还有一个导航后退按钮。navigation bar example

我的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看起来像这样......我几乎没碰过这部分代码......我唯一尝试过的就是&#39; ClearNavigationStack&#39;方法,但这是一个失败。

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。

我欢迎任何建议,因为过去两天我一直在讨论这个问题。

编辑:刚才,我已经设法隐藏了#34;通过将我的MainPage设置为类似

的导航堆栈
App.Current.MainPage = new MasterMainPage();

但它看起来像一个代码味道,看起来像一个可怕的黑客。另外,我不太确定它是否会违反&#34;我正在遵循的概念...我想这个导航堆栈永远不会消失,因为我将在主细节页面内做其他导航堆栈。

1 个答案:

答案 0 :(得分:1)

从图片中我看到您在导航页面中有Master / Detaied页面。 Xamarin并不建议这样做。我不知道你将如何在MVVM Light中做到这一点,但在常规表格中,你有几种选择来实现你想要的:

  1. 如果您需要返回登录或注册页面,请使用

    p-value=0.7527
  2. 然后你可以popmodal回到它们但是在这种情况下硬件按钮仍然会带你登录。导航到主 - 详细信息页面后,可以使用方法2的一部分清除堆栈但要小心 - 如果页面是根目录和当前显示的页面,则无法从堆栈中删除页面,因此您只需在清除后定期导航堆栈登录页面不显示。 我不建议将该选项作为&#34;模态视图通常是临时的,并且只在屏幕上播放足够长的时间以便用户完成任务。&#34;

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

    1. 如果您不需要返回,可以使用以下清除导航堆栈,它也会删除后退按钮

      fitdistr(x, "gamma")