Search code examples
c#androidxamlmauimaui-community-toolkit

Unable to Open Popup in Maui From Within OnAppearing


Problem:

From within the OnAppearing method in a MAUI content page, calling the Maui Community Toolkit method: ShowPopup causes an exception: System.InvalidOperationException: 'Could not locate MauiContext.'

It seems to work just fine when used not in the OnAppearing method.

The ultimate goal is to display the popup (with a spinner) while the page is loading with data, and then remove it once the data has been loaded. Currently I'm loading data via the OnAppearing method.

Maui Community Toolkit version: 5.0.0 Android / Maui Version: net7.0-android Dotnet Version: 7.0

Content Page:

public partial class FilesInMediaStorePage : ContentPage
{
    public FilesInMediaStorePage()
    {
        InitializeComponent();
        BindingContext = new FilesInMediaStoreViewModel();
    }
    protected override void OnAppearing()
    {
        this.ShowPopup(new SpinnerPopup()); //causes the exception: System.InvalidOperationException: 'Could not locate MauiContext.'
        Task.Run(async () =>
        {
            this.ShowPopup(new SpinnerPopup()); //has no affect
            await this.ShowPopupAsync(new SpinnerPopup()); //has no affect
        });
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        this.ShowPopup(new SpinnerPopup()); //works just fine
    }
}

Popup:


<toolkit:Popup
    x:Class="FullSail.Views.SpinnerPopup"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    CanBeDismissedByTappingOutsideOfPopup="True"
    
    >
    <VerticalStackLayout>
        <ActivityIndicator IsRunning="True" />
        <Label TextColor="Red" Text="Loading..." />
        <Label TextColor="Red" Text="This is a very important message!" />
        <Button Text="OK" 
                Clicked="OnOKButtonClicked" />
    </VerticalStackLayout>
</toolkit:Popup>

I tried to use both the void and the async method of the method - and also calling the method within a Task with no luck.

I also looked for a different suitable base methods to override instead of the OnAppearing, however no others seemed to kick off on page load.


Solution

  • No, that won't work. You've asked Maui to simultaneously get ready to show the page, AND block the page while you show a Popup.

    • Instead, have spinner as an element on page. Let the page appear with minimal content while needed data is prepared inside Task.Run.
    • Any changes that affect UI must be deferred until you use Dispatcher to get back to MainThread.
    // --- Inside "OnAppearing" ---
    // make spinner (element on page) visible.
    ...
    Task.Run(() =>
    {
        // Prepare data here, as local variables that are not used by UI.
        // Do not touch any UI element, or any code property bound to a UI element!
        ...
    
        // When data is ready:
        Dispatcher.Dispatch(() =>
        {
            // Make changes to UI elements and bound properties here.
            // (From the local variables you prepared above.)
            ...
            // hide spinner
            ...
        }
    }
    ```cs