FreshMVVM 在 ContentPage 和 TabbedPage 之间切换导航堆栈

Posted

技术标签:

【中文标题】FreshMVVM 在 ContentPage 和 TabbedPage 之间切换导航堆栈【英文标题】:FreshMVVM Switching Navigation Stacks Between ContentPage and TabbedPage 【发布时间】:2021-03-06 17:57:58 【问题描述】:

我正在将应用转换为使用非 MVVM 格式的 FreshMVVM。当应用程序启动时,会出现一个登录页面,然后在登录后,会出现一个标签页,其中包含从每个标签页上的按钮调用的模式页面。

鉴于我正在遵循的过程,我认为这将是使用 Michael Ridland 的过程来切换 NavigationStacks (https://github.com/rid00z/FreshMvvm#switching-out-navigationstacks-on-the-xamarinforms-mainpage) 的完美选择,但这些步骤似乎缺少很多重要的说明,这些步骤不在 GitHub 上的示例应用程序中。

在我的App.xaml.xs 文件中,我有以下代码:

public App()
        
            InitializeComponent();
            var loginPage = FreshMvvm.FreshPageModelResolver.ResolvePageModel<LoginPageModel>();
            var loginContainer = new STNavigationContainer(loginPage, NavigationContainerNames.AuthenticationContainer);
            var homePageViewContainer = new FreshTabbedNavigationContainer(NavigationContainerNames.MainContainer);

            MainPage = loginContainer;
        

        public FreshTabbedNavigationContainer(string navigationServiceName)
        
            NavigationServiceName = navigationServiceName;
            RegisterNavigation();
        

        protected void RegisterNavigation()
        
            FreshIOC.Container.Register<IFreshNavigationService>(this, NavigationServiceName)
        

        public void SwitchOutRootNavigation(string navigationServiceName)
        
            IFreshNavigationService rootNavigation =
                FreshIOC.Container.Resolve<IFreshNavigationService>(navigationServiceName);
        
        public void LoadTabbedNav()
        
            var tabbedNavigation = new FreshTabbedNavigationContainer();
            tabbedNavigation.AddTab<CharactersPageModel>("Characters", "characters.png");
            tabbedNavigation.AddTab<AdventuresPageModel>("Adventures", "adventures.png");
            tabbedNavigation.AddTab<AccountPageModel>("Account", "account.png");
            MainPage = tabbedNavigation;
        
 public class NavigationContainerNames
    
        public const string AuthenticationContainer = "AuthenticationContainer";
        public const string MainContainer = "MainContainer";
    

这似乎与 ReadMe.md 中提供的步骤相匹配,但对 NavigationServiceName 的调用会返回错误,因为没有关于创建此类或它应该包含什么的说明,我也不清楚在哪里FreshTabbedNavigationContainerSwitchOutRootNavigation 将被调用。

有没有人能够让它工作?我在这方面缺少哪些步骤?

编辑:我忘了我已经扩展了FreshNavigationContainter 类和FreshNavigationPage 类。这是我的扩展类:

STNavigationContainer:

public class STNavigationContainer : FreshNavigationContainer
    
        public STNavigationContainer(Page page) : base(page)
        
        

        public STNavigationContainer(Page page, string navigationPageName) : base(page, navigationPageName)
        
        

        protected override Page CreateContainerPage(Page page)
        
            if (page is NavigationPage || page is MasterDetailPage || page is TabbedPage)
                return page;

            return new STNavigationPage(page);
        
    

STNavigationPage:

public class STNavigationPage : NavigationPage
    
        public STNavigationPage()
        
                
        

        public STNavigationPage(Page page) : base(page)
        
            BarBackgroundColor = Color.FromHex("#2DAFEB");
            BarTextColor = Color.FromHex("#C9371D");
        
    

编辑 2:重新阅读 https://michaelridland.com/xamarin/implementing-freshmvvm-mvvm-xamarin-forms/ 和 Github 帖子,我发现我需要在自定义导航服务中执行此操作,所以这是我更新的代码。

App.xaml.cs:

    public partial class App : Application
    
        public static Account account = new Account();

        public App()
        
            InitializeComponent();
            FreshIOC.Container.Register<IDatabaseService, DatabaseService>();

            if (account.Equals(null))
            
                LoadSingleNav();
            
            else
            
                LoadTabbedNav();
            

            var navPage = new NavigationPage(new LoginPage())
            
                BarBackgroundColor = Color.FromHex("#2DAFEB"),
                BarTextColor = Color.FromHex("#C9371D")
            ;
            NavigationPage.SetHasNavigationBar(navPage.CurrentPage, false);
            MainPage = navPage;

            MainPage = loginContainer;
        

        public FreshTabbedNavigationContainer(string navigationServiceName)
        
            NavigationContainerNames = navigationServiceName;
            RegisterNavigation();
        

        protected override void OnStart()
        
        

        protected override void OnSleep()
        
        

        protected override void OnResume()
        
        
    

CustomNavService.cs:

    public class CustomNavService : NavigationPage, IFreshNavigationService
    
        FreshTabbedNavigationContainer _tabbedNavigationPage;
        Page _charactersPage, _adventuresPage, _accountPage;
        public CustomNavService(Page page) : base (page)
        
            NavigationServiceName = "CustomNavService";
            LoadTabbedNav();
            CreateLoginPage();
            RegisterNavigation();
        

        public string NavigationServiceName  get; private set; 

        public void NotifyChildrenPageWasPopped()
        
            throw new NotImplementedException();
        

        public async Task PopPage(bool modal = false, bool animate = true)
        
            if (modal)
                await Navigation.PopModalAsync (animate);
            else
                await Navigation.PopAsync (animate);
        

        public async Task PopToRoot(bool animate = true)
        
            await Navigation.PopToRootAsync(animate);
        

        public async Task PushPage(Page page, FreshBasePageModel model, bool modal = false, bool animate = true)
        
            if (modal)
                await Navigation.PushModalAsync(page, animate);
            else
                await Navigation.PushAsync(page, animate);
        

        public Task<FreshBasePageModel> SwitchSelectedRootPageModel<T>() where T : FreshBasePageModel
        
            IFreshNavigationService rootNavigation =
                FreshIOC.Container.Resolve<IFreshNavigationService>(NavigationServiceName);
        

        public void LoadTabbedNav()
        
            _tabbedNavigationPage = new FreshTabbedNavigationContainer();
            _charactersPage = _tabbedNavigationPage.AddTab<CharactersPageModel>("Characters", "characters.png");
            _adventuresPage = _tabbedNavigationPage.AddTab<AdventuresPageModel>("Adventures", "adventures.png");
            _accountPage = _tabbedNavigationPage.AddTab<AccountPageModel>("Account", "account.png");
            this = _tabbedNavigationPage;
        
        private void CreateLoginPage()
        
            var loginPage = FreshPageModelResolver.ResolvePageModel<LoginPageModel>(null);
            var loginContainer = new STNavigationContainer(loginPage, CustomNavService.NavigationContainerNames.AuthenticationContainer);
            var homePageViewContainer = new FreshTabbedNavigationContainer(CustomNavService.NavigationContainerNames.MainContainer);

        

        protected void RegisterNavigation()
        
            FreshIOC.Container.Register<IFreshNavigationService>(this, NavigationServiceName);
        

        public class NavigationContainerNames
        
            public const string AuthenticationContainer = "AuthenticationContainer";
            public const string MainContainer = "MainContainer";
        

    

我的自定义导航服务中的SwitchSelectedRootPageModel&lt;T&gt; 任务显示需要返回,我不太清楚LoadTabbedNav 应该包含什么this;该示例显示 this.Detail,但这显示为无效引用。

【问题讨论】:

【参考方案1】:

查看我们的 FreshMvvm 实现,我们的 SwitchSelectedRootPageModel 如下所示:

public Task<FreshBasePageModel> SwitchSelectedRootPageModel<T>() where T : FreshBasePageModel

    return Task.FromResult<FreshBasePageModel>(null);

我们的代码正确使用

this.Detail = _tabbedNavigationPage;

所以如果你得到一个无效的引用,肯定还有其他东西丢失了。

【讨论】:

以上是关于FreshMVVM 在 ContentPage 和 TabbedPage 之间切换导航堆栈的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin Forms MvvM框架之FreshMvvM翻译一

Xamarin.Forms ContentPage生命周期的困惑

Xamarin XAML语言教程基本页面ContentPage占用面积

我可以在 TabbedPage 内的 ContentPage 中放置另一个 ContentPage 吗?

Xamarin.Forms:我什么时候应该在ContentPage中取消控件的事件

在 Xamarin.Forms 中为 ContentPage 使用自定义基类