Login Screen before Master Detail View in Xamarin

280 Views Asked by At

I am trying to write a xamarin app that will display a login page before a master detail page but I am running into issues. Right now I have my app.xaml calling an appbootstrapper as follows:

public App()
        {
            this.InitializeComponent();

            RxApp.SuspensionHost.CreateNewAppState = () => new AppBootstrapper();
            RxApp.SuspensionHost.SetupDefaultSuspendResume();

            this.MainPage = RxApp.SuspensionHost
                                 .GetAppState<AppBootstrapper>()
                                 .CreateMainPage();
        }

        /// <summary>Gets the Router associated with this Screen.</summary>
        public RoutingState Router { get; } = new RoutingState();

With the app bootstrapper as follows:

public class AppBootstrapper : ReactiveObject, IScreen
    {
        public AppBootstrapper(IMutableDependencyResolver dependencyResolver = null)
        {
            SetupLogging();
            this.RegisterParts(dependencyResolver ?? Locator.CurrentMutable);
            this.Router.Navigate.Execute(new LoginPageViewModel(this));
        }

        /// <summary>Gets the Router associated with this Screen.</summary>
        public RoutingState Router { get; } = new RoutingState();

        public Page CreateMainPage()
        {
            return new RoutedViewHost();
        }

        private static void SetupLogging()
        {
            var logger = new Logger { Level = LogLevel.Debug };
            Locator.CurrentMutable.RegisterConstant(logger, typeof(ILogger));
        }

        private void RegisterParts(IMutableDependencyResolver dependencyResolver)
        {
            dependencyResolver.RegisterConstant(this, typeof(IScreen));

            dependencyResolver.Register(() => new LoginPage(), typeof(IViewFor<LoginPageViewModel>));
            dependencyResolver.RegisterConstant(new LoginService(), typeof(ILoginService));
        }
    }

This gets me to my login screen no problem, and I can perform my login operation. Then, once login is successful, I try to navigate to the master detail page, but this is where I run into issues.

public LoginPageViewModel(IScreen screen)
        {
            this.loginService = Locator.Current.GetService<ILoginService>();
            this.HostScreen = screen ?? Locator.Current.GetService<IScreen>();
            this.PrepareObservables();
        }

........................................................

private void PrepareObservables()
        {
            ...

            this.LoginCommand = ReactiveCommand.CreateFromTask(
                async execute =>
                {
                    var loginSuccessful = await this.loginService.Login(this.Username, this.Password);
                    if (loginSuccessful)
                    {
                        this.HostScreen.Router.NavigateBack.Execute().Subscribe();
                    }
                }, canExecuteLogin);
...

You can see that my login command is trying to perform a navigate and reset to go to the Main Page (which is my master detail page). This is not working and is resulting in an unhandled exception stating:

An object implementing IHandleObservableErrors has errored, thereby breaking its observable pipeline. To prevent this, ...>

Does anyone know what to do here? I need a good pattern for handling the use case of Login -> Master Detail Page in Xamarin Forms using ReactiveUI. Thanks.

1

There are 1 best solutions below

0
Rodney Littles On
            this.LoginCommand = ReactiveCommand.CreateFromTask(
                async execute =>
                {
                    var loginSuccessful = await this.loginService.Login(this.Username, this.Password);
                    if (loginSuccessful)
                    {
                        this.HostScreen.Router.NavigateBack.Execute().Subscribe();
                    }
                }, canExecuteLogin);

The above code is navigating back on successful login. I think you mean to use Router.NavigateAndReset.Execute(new MainPageViewModel()).Subscribe();