John D
John D

Reputation: 138

how to navigate in OnAppearing() method?

I want to avoid putting my OnBoarding view in navigation stack to fix the problem of pressing the back button. In my MainPage I check if OnBoarding should appear or not. If true, I call PushModalAsync method in OnAppearing method. But the App crash with the following exception:

Objective-C exception thrown.  Name: System.InvalidOperationException Reason: Window should have a UIWindow set. (System.InvalidOperationException)
   at Microsoft.Maui.Controls.Window.get_NativeWindow()
   at Microsoft.Maui.Controls.Platform.ModalNavigationManager.EndEditing()
   at Microsoft.Maui.Controls.Platform.ModalNavigationManager.PushModalAsync(Page modal, Boolean animated)
   at Microsoft.Maui.Controls.Window.NavigationImpl.OnPushModal(Page modal, Boolean animated)
   at BytePesaApp.MainPage.OnAppearing() in MainPage.xaml.cs:line 18
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
   at Foundation.NSAsyncSynchronizationContextDispatcher.Apply()

Here is the code implementation:

public partial class MainPage : ContentPage
{

    public MainPage()
    {
        InitializeComponent();
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();

        if (ShouldShowOnBoardingPage() == true)
        {
            await Navigation.PushModalAsync(new OnBoardingPage(), false);
        }
    }


    private bool ShouldShowOnBoardingPage()
    {
        return VersionTracking.IsFirstLaunchEver;
    }
}

Upvotes: 3

Views: 8220

Answers (3)

Kanat
Kanat

Reputation: 21

one of the decisions is to use task:

protected override async void OnAppearing()
{
    base.OnAppearing();

    if (ShouldShowOnBoardingPage() == true)
    {
        Task.Run(async () => 
        {
             await Navigation.PushModalAsync(new OnBoardingPage(), false);
        });
        
    }
}

Upvotes: 2

Tobias Leppkes
Tobias Leppkes

Reputation: 29

The Loaded-Event is fired after OnAppearing(); unfortunately, there is no OnLoad() to override, so you have to use the event:

public partial class MainPage : ContentPage
{

    public MainPage()
    {
        InitializeComponent();

        this.Loaded += MainPage_Loaded;
    }

    protected async void MainPage_Loaded(object sender, EventArgs e)
    {
        if (ShouldShowOnBoardingPage() == true)
        {
            await Navigation.PushModalAsync(new OnBoardingPage(), false);
        }
    }

    private bool ShouldShowOnBoardingPage()
    {
        return VersionTracking.IsFirstLaunchEver;
    }
}

Upvotes: 3

ToolmakerSteve
ToolmakerSteve

Reputation: 21243

It sounds like Maui is not in a good state to navigate, until OnAppearing finishes. DEFER the navigation like this:

Dispatcher.Dispatch(async() =>
    await Navigation.PushModalAsync(new OnBoardingPage(), false);
);

This code will be queued, and will run after OnAppearing returns.


An ALTERNATIVE is to replace the MainPage during OnBoarding.
In App.xaml.cs:

if (ShouldShowOnBoardingPage() == true)
    MainPage = new OnBoardingPage();
else
    MainPage = new MainPage();

Then when OnBoarding is complete:

    Application.Current.MainPage = new MainPage();

I prefer the latter approach, if possible.

Upvotes: 4

Related Questions