MAUI : await Shell.Current.GoToAsync with Modal presentation doesn't work as expected

836 Views Asked by At

I'm quite a newbie with MAUI and Mobile Apps development and I'm facing a forced migration from Xamarin.Forms to MAUI after recent iOS updates. The problem is that modal navigation with MAUI doesn't work as I would expect. The piece of code is this:

private async void btnSend_Tapped(object sender, EventArgs e)
{
    await Shell.Current.GoToAsync("//MainPage/TakePicture/SendPicture/OtpCheck");

    if (Variables.CurrentPicture.Otp == 0)
    {
        ....
    }

    await Shell.Current.Navigation.PopToRootAsync();

in the xaml of OtpCheck page I set:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             ...
             x:Class="SkyObservers.Pages.OtpCheck"
             Shell.PresentationMode="Modal">

I would expect that "if(Variables..." would be reached only when OtpCheck page is closed, but it doesn't work like this. The page is loaded and then suddenly disappears, because "PopToRootAsync" is immediately reached. In Xamarin.Forms didn't work like that, so I tried also

await Navigation.PushModalAsync(new OtpCheck());

instead of

await Shell.Current.GoToAsync("//MainPage/TakePicture/SendPicture/OtpCheck");

but the result is the same.

P.S. The route of the page is (hopefully) correctly registered in AppShell.xaml:

<ShellContent Title="SkyObservers" ContentTemplate="{DataTemplate local:MainPage}" Route="MainPage" />
<ShellContent Title="Take New Picture" ContentTemplate="{DataTemplate pages:TakePicture}" Route="MainPage/TakePicture" />
<ShellContent Title="Send Picture" ContentTemplate="{DataTemplate pages:SendPicture}" Route="MainPage/TakePicture/SendPicture" />
<ShellContent Title="Check OTP" ContentTemplate="{DataTemplate pages:OtpCheck}" Route="MainPage/TakePicture/SendPicture/OtpCheck" />

and in AppShell.xaml.cs

public AppShell()
{
    InitializeComponent();

    Routing.RegisterRoute("MainPage/TakePicture", typeof(TakePicture));
    Routing.RegisterRoute("MainPage/TakePicture/SendPicture", typeof(SendPicture));
    Routing.RegisterRoute("MainPage/TakePicture/SendPicture/OtpCheck", typeof(OtpCheck));
}
2

There are 2 best solutions below

0
On

Glad you have a good solution using Popup! Here, I also share a workaround using TaskCompletionSource without maui popup.

This is the code-behind for OtpCheck page,

public partial class OtpCheck : ContentPage
{
    TaskCompletionSource<string> _taskCompletionSource;
    public Task<string> ModalDismissedTask => _taskCompletionSource.Task;
    public string ReturnValue { get; set; }

    public OtpCheck()
    {
        InitializeComponent();
    }

    async void Button_Clicked(System.Object sender, System.EventArgs e)
    {
        ReturnValue = "233";
        await Shell.Current.Navigation.PopModalAsync();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        _taskCompletionSource = new TaskCompletionSource<string>();
    
    }

    protected async override void OnDisappearing()
    {
        _taskCompletionSource.SetResult(ReturnValue);
        base.OnDisappearing();   
    }
}

And use this to perform navigation:

    var modalPage = new OtpCheck();
    await Navigation.PushModalAsync(modalPage);
    var rvalue = await modalPage.ModalDismissedTask;

You could get the return value from OtpCheck page now!

Hope it helps!

1
On

I have solved the problem by transforming OtpCheck page in a CommunityToolkit.Maui.Views.Popup and waiting the result. Xaml code of the page:

<?xml version="1.0" encoding="utf-8" ?>
<views:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:resources="clr-namespace:SkyObservers.Localization"
         xmlns:views="clr-namespace:CommunityToolkit.Maui.Views assembly=CommunityToolkit.Maui"
         x:Class="SkyObservers.Pages.OtpCheck"
         CanBeDismissedByTappingOutsideOfPopup="False"
         Shell.PresentationMode="Modal">

CodeBehind for opening and waiting popup's result:

bool result = (bool) await this.ShowPopupAsync(new OtpCheck());