Show Popup in .Net Maui

1.9k Views Asked by At

I am trying to use the .Net Maui community toolkit to show a Popup as a loading page when computing in page and between pages. However when I execute the code it does not show the popup on the device using this.ShowPopUpAsync(popup) or Application.Current.MainPage.ShowPopupAsync(popup).

My PopUp Xaml is

<?xml version="1.0" encoding="utf-8" ?>
<xct:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           x:Class="DailyBudgetMAUIApp.Handlers.PopUpPage"
           xmlns:xct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
           CanBeDismissedByTappingOutsideOfPopup="False"
           Color="Transparent">
    <VerticalStackLayout HeightRequest="300" WidthRequest="200">
        <ActivityIndicator IsRunning="True" IsVisible="True" VerticalOptions="StartAndExpand" HorizontalOptions="Center" BackgroundColor="Transparent"  Margin="0,100,0,0" Color="{DynamicResource Primary}" Scale="1">
            </ActivityIndicator>
            <Label Text="Loading ..." FontAttributes="Bold" FontSize="Medium" VerticalOptions="Center" HorizontalOptions="Center" FontFamily="OpenSansSemibold" TextColor="{DynamicResource Light}" Margin="0,20,0,0"/>
        </VerticalStackLayout>
</xct:Popup>

With the Xaml.cs

public partial class PopUpPage : Popup
{
    public PopUpPage()
    {
         InitializeComponent();
    }
}

And then I am calling a method where I want to show the popup in something like this

private async void UndoCreateBudget(int BudgetID)
{
    Popup popup = new PopUpPage();
    await Application.Current.MainPage.ShowPopupAsync(popup);
    

    //Call my api and do some stuff


    popup.Close();

}
3

There are 3 best solutions below

4
On

I have tested your code. The Popup is valid. And using this way to call it - it will show up.

Tested it on Android and Windows. I am almost certain that if you place a breakpoint in this method: UndoCreateBudget it will never get hit at first place. So you should check this first.

Anyway, I am not writing this to tell you it will work. You have a deadlock right there.

This line:

await Application.Current.MainPage.ShowPopupAsync(popup);

Will very tricky lure you to await it, when you hover over it. And it does not take into consideration that you have this line in the xaml:

CanBeDismissedByTappingOutsideOfPopup="False"

You have to run this task. Run it, not await it. It waits for the popup to close. And this kind of popup you have will never close on its own.

You will never get to the API call. And you will lock your interface.

2
On

If I may suggest another way of loading data. Use a Modal Window. You don't get that grayed out background that can be a bit off putting to some users, and you get a reusable View for all kinds of API calls. This means you do the API calls in the loading view and not in the Content View. Then again you can send an event that trigger when the loading is opened, so there are possibilities for that too.

public class LoadingPage : ContentPage
{
    private ActivityIndicator _indicator;
    private VerticalStackLayout _stackLayout;

    public LoadingPage()
    {
        BackgroundColor = new Color(0, 0, 0, 1);

        _indicator = new ActivityIndicator
        {
            IsRunning = true,
            Color = Colors.Black,
            Scale = 1,
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.Center
        };

        var loadingLabel = new Label()
        {
            Text = "Loading...",
            TextColor = Colors.Black,
            HorizontalOptions = LayoutOptions.Center
        };

        _stackLayout = new VerticalStackLayout
        {
            WidthRequest = 200,
            HeightRequest = 300,
            BackgroundColor = new Color(0, 0, 0, 1),
            Children =
            {
                _indicator,
                loadingLabel
            }
        };

        Content = _stackLayout;
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        await Task.Delay(5000);
        await Dismiss();
    }

    public async Task Dismiss()
    {
        await Navigation.PopModalAsync();
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();

        _indicator.IsRunning = false;
        _stackLayout.IsVisible = false;
    }

    protected override bool OnBackButtonPressed()
    {
        // Return true to prevent the back button from closing the page
        return true;
    }
}

You call it from your method like this

var page = new LoadingPage();
await Navigation.PushModalAsync(page, false);

Here is a sample how it can look like

enter image description here

0
On

I am here to share another way of using MessagingCenter to display and dismiss popup for your scenario.

First, Publish a message

private async void UndoCreateBudget(int BudgetID)
{
    Popup popup = new PopUpPage();
    await Application.Current.MainPage.ShowPopupAsync(popup);
    
    MessagingCenter.Send<MainPage>(this, "display");
    //Call my api and do some stuff

    MessagingCenter.Send<MainPage>(this, "dismiss");
}

Then Subscribe to a message

public MainPage()
{
    InitializeComponent();
    MessagingCenter.Subscribe<MainPage>(this, "start", (e) =>
    {

        popup = new PopUpPage();
        this.ShowPopup(popup);
    });

    MessagingCenter.Subscribe<MainPage>(this, "close", (e) =>
    {
        popup.Close();
    });
}

For .NET MAUI 7, you could use Messenger