Skip to content

[Bug]: Maui RoutedViewModel, NavigateAndReset doesn't change views (for Windows at least) #3939

Open
@limefrogyank

Description

@limefrogyank

Describe the bug 🐞

I'm using Maui Hybrid on Windows. I'm using both Maui native views and some Blazor views, too. I've got a ReactiveUI.Maui.RoutedViewHost to control the navigation via native views. I have some code that runs on startup that checks for a login status and changes the start page based on that:

d2lService.HasAccess.ObserveOn(RxApp.MainThreadScheduler).Subscribe(async x =>
            {
                if (x)
                {
                    Router
                        .NavigateAndReset
                        .Execute(new RootViewModel())
                        .Subscribe();
                }
                else
                {
                    Router
                       .NavigateAndReset
                       .Execute(new WebViewViewModel())
                       .Subscribe();
                }
            });

This part works just fine. If my token is no longer valid, my HasAccess observable will return false and the app will start with a page that contains a WebView. If I do have access, the start page is a page that contains more complicated stuff.

What doesn't work is the transition between the two. When I "log in" via the webview page and then the HasAccess observable flips, the viewmodel changes but the view stays the same. i.e. I now have a RootViewModel in the stack, but the view is still for the WebViewViewModel.

Step to reproduce

Create an AppBootstrapper.cs containing this:

internal class AppBootstrapper : ReactiveObject, IScreen
    {
        //private static required IDisposable _d;

        public RoutingState Router { get; protected set; }

        public BehaviorSubject<bool> HasAccess = new BehaviorSubject<bool>(false);
        
        public AppBootstrapper()
        {
            Router = new RoutingState();
            Locator.CurrentMutable.RegisterConstant(this, typeof(IScreen));

            Locator.CurrentMutable.Register(() => new WebViewView(), typeof(IViewFor<WebViewViewModel>)); // webview for logging in
            Locator.CurrentMutable.Register(()=> new RootPage(), typeof(IViewFor<RootViewModel>)); // root page

 Observable.Timer(TimeSpan.FromSeconds(20)).Subscribe(x=> HasAccess.OnNext(true));

            HasAccess.ObserveOn(RxApp.MainThreadScheduler).Subscribe(async x =>
            {
                if (x)
                {
                    Router
                        .NavigateAndReset
                        .Execute(new RootViewModel())
                        .Subscribe();
                }
                else
                {
                    Router
                       .NavigateAndReset
                       .Execute(new WebViewViewModel())
                       .Subscribe();
                }
            });

        }

        public static ReactiveUI.Maui.RoutedViewHost CreateMainPage(RoutingState router)
        {
            var host = new ReactiveUI.Maui.RoutedViewHost();
            host.Router = router;
            return host;
        }

    }

You'll then have to create two pages (ReactiveContentPage) and viewmodels that implement IRoutableViewModel. The page should start with one, then the timer should try to reset navigation to the new page.

Reproduction repository

https://github.com/reactiveui/ReactiveUI

Expected behavior

You should see two different pages with an interval of 20 seconds between them.

Screenshots 🖼️

No response

IDE

No response

Operating system

Windows

Version

11 latest non-dev

Device

No response

ReactiveUI Version

20.1.63

Additional information ℹ️

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions