Forum Xamarin.Forms

FreshMVVM Switching Navigation Stacks Between ContentPage and TabbedPage

avagduavagdu Member
edited November 2020 in Xamarin.Forms

I'm converting an app to use FreshMVVM from a non-MVVM format. When the app launches, there is a login page, then after login, a tabbed page with modal pages called from the buttons on each tabbed page.

Given the process I'm following, I figured that this would be a perfect option to use @MichaelRidland 's process to switch out NavigationStacks (github rid00z/FreshMvvm#switching-out-navigationstacks-on-the-xamarinforms-mainpage), but the steps appear to be missing quite a few important instructions, and these steps are not in the sample app on the GitHub.

In my App.xaml.xs file, I have the following code:

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";
    }

I have extended the FreshNavigationContainter class and the FreshNavigationPage class. Here are my extended classes:

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");
        }
    }

This seems to match with the steps provided in the ReadMe.md, but the calls to NavigationServiceName return an error, since there's no instruction on creating such a class or what it should contain, nor am I clear on where the FreshTabbedNavigationContainer or SwitchOutRootNavigation would be called.

Has anyone been able to get this to work? What steps am I missing on this?

Answers

  • avagduavagdu Member

    Re-reading MichaelRidland dot com/xamarin/implementing-freshmvvm-mvvm-xamarin-forms/ and the Github post, I was able to figure out that I needed to do this in a Custom Navigation Service, so here is my updated code.

    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";
            }
    
        }
    

    The SwitchSelectedRootPageModel<T> task in my Custom Navigation Service is showing that a return is needed, and I'm not quite clear on what the LoadTabbedNav is supposed to include with the this; the example shows this.Detail, but that's showing as an invalid reference.

Sign In or Register to comment.