Xamarin.Forms Page.DisplayAlert in Page.OnAppearing

I am unable to get a DisplayAlert popup to show within the OnAppearing callback of a Xamarin.Forms Page. Here is what I have tried so far:

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

    this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

Considering DisplayAlert is technically an async function, returning a Task, I have also tried the following:

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

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

However, neither seem to work. My guess is it doesn’t really make much sense to make OnAppearing to be async at all, since it does not return a Task, and so this turns into a fire-and-forget situation with respect to the calling framework. Same by extension goes for DisplayAlert in this context. So on the one hand I don’t really expect this to work at all, but in case I’m wrong, is it possible to use DisplayAlert in OnAppearing?

Update

Seems I failed to provide some context. I’m working from an Xamarin.Forms Shell template; though I have already developed some past the initial template, so it’s hard to say at this point to what extent the Shell itself contributes at all. Also, my main target platform is Android.

That all being said, I was able to start a blank app template and try the above code in the otherwise fresh MainPage — both worked fine. I still do not know why they do not work in my actual application context, so I am going to do some digging there and report back any findings.

Enquirer: Bondolin

||

Solution #1:

Took my little experiment one step further and tried the basic Shell template app.

Adding the OP sample DisplayAlert code to the main ItemsPage codebehind did not work. If I did this,

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

    if (viewModel.Items.Count == 0)
        viewModel.LoadItemsCommand.Execute(null);

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");
}

the items would load but no dialog would show. If instead I moved the dialog up,

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

    await this.DisplayAlert("Alert", "Consider yourself alerted", "OK");

    if (viewModel.Items.Count == 0)
        viewModel.LoadItemsCommand.Execute(null);
}

the dialog would not show nor would the items load. So the async execution died and/or wandered off into the great big bit bucket up in the sky.

I then tried adding the DisplayAlert sample to the main AppShell page, only to find the OnAppearing override does not get called at all for the Shell class. This was confirmed by the following open Shell issue: [Bug] Shell – OnAppearing not executing
#6486
.

Finally, just as a final stretch, I tried hacking a call to DisplayAlert into the async callback executed by LoadItemsCommand in ItemsPage.OnAppearing. A bit nasty since it’s passing the view into the view-model, which is directly against good MVVM in the first place —

async Task ExecuteLoadItemsCommand(ItemsPage view)
{
    if (IsBusy)
        return;

    IsBusy = true;

    try
    {
        Items.Clear();
        var items = await DataStore.GetItemsAsync(true);
        foreach (var item in items)
        {
            Items.Add(item);
        }

        await Device.InvokeOnMainThreadAsync(async () =>
            await view.DisplayAlert("Alert", "Consider yourself alerted", "OK"));
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
    finally
    {
        IsBusy = false;
    }
}

Don’t stone me.

This didn’t seem to have any better results. Just like when calling DisplayAlert directly in the page’s OnAppearing, the execution just took a lunch break. The spinner bound to the IsBusy flag never stopped, so that indicates the finally block never even got executed.

My general understanding at this point is that there is currently some limitation in the type of async operations that can be done from a Shell’s ContentPage. Even the awaited call to DataStore.GetItemsAsync is not truly asynchronous in this implementation, so I somewhat doubt it would actually work given a real, asynchronous database connection. I have been able to get DisplayAlert working in the context of a normal event handler, so I think the issue is scoped to whatever initialization logic goes on during OnAppearing and whatever it ends up directly calling or scheduling. Much of this is just observational speculation, but I may forward this on as a bug, unless someone can offer a more complete analysis.

Update (for closure, OCD, documentation, etc)

As the comments indicate, the version of Xamarin.Forms I was using (4.2.0) had a bug that has been fixed in later versions.

Respondent: Bondolin

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.