dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.25k stars 1.76k forks source link

Alerts do not display from ctor or OnAppearing when not in a NavPage/Shell #12970

Open mattleibow opened 1 year ago

mattleibow commented 1 year ago

Description

Seems that the alerts are fired correctly and then added to the _pendingActions. However, the FlushPendingActions method only fires when the NavigatedTo even is invoked - and this only happens when in a nav page or in shell.

Steps to Reproduce

  1. In the sandbox app
  2. Use this code in the MauiProgram.cs:
    class App : Application
    {
        protected override Window CreateWindow(IActivationState activationState) =>
            new Window(new MainPage());
    }
  3. Use this code in the MainPage.xaml.cs:
    protected override void OnAppearing()
    {
        base.OnAppearing();
        DisplayAlert("A", "B", "C");
    }

Link to public reproduction project repository

maui repo

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS, Android, Windows, macOS, Other (Tizen, Linux, etc. not supported by Microsoft directly)

Affected platform versions

All version as this is xplat code

Did you find any workaround?

No response

Relevant log output

No response

mattleibow commented 1 year ago

@PureWeen not sure the overall navigation / alerts plan, but saw this while trying to create tests for https://github.com/dotnet/maui/pull/12910

jsuarezruiz commented 1 year ago

Same or similar to https://github.com/dotnet/maui/issues/12739

ghost commented 1 year ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ShariatPanah commented 1 year ago

any update on this guys? i have the same problem

jeremy-visionaid commented 1 year ago

Yup, I just hit this one too.

jeremy-visionaid commented 1 year ago

@mattleibow I find this to be even worse than the title...

On Windows, OnNavigatedTo actually fires in my app, but the alert is still not displayed. If you try to work around it by adding an (insufficient) delay by using a timer or a Task.Delay, then it can cause a crash (8.0.0-rc.1.9171):

   at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|20_0(Int32 hr) in WinRT\ExceptionHelpers.cs:line 103
   at WinRT.ExceptionHelpers.ThrowExceptionForHR(Int32 hr) in WinRT\ExceptionHelpers.cs:line 105
   at ABI.Microsoft.UI.Xaml.Controls.IContentDialogMethods.ShowAsync(IObjectReference _obj) in ABI.Microsoft.UI.Xaml.Controls\IContentDialogMethods.cs:line 51
   at Microsoft.UI.Xaml.Controls.ContentDialog.ShowAsync() in Microsoft.UI.Xaml.Controls\ContentDialog.cs:line 527
   at Microsoft.Maui.Controls.Platform.AlertManager.AlertRequestHelper.<ShowAlert>d__14.MoveNext() in Microsoft.Maui.Controls.Platform\AlertManager.cs:line 209
   at Microsoft.Maui.Controls.Platform.AlertManager.AlertRequestHelper.<OnAlertRequested>d__11.MoveNext() in Microsoft.Maui.Controls.Platform\AlertManager.cs:line 94
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state) in /_/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:line 1914
   at Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.<>c__DisplayClass2_0.<Post>b__0()

So, seems like there's a pretty big problem in how to know how when it's valid to display an alert... I can put in a delay of a second, and that works OK on my machine (anything much shorter is unreliable) - but I don't know if it's sufficient for other cases.

homeyf commented 1 year ago

Verified this issue with Visual Studio Enterprise 17.8.0 Preview 2.0. Can repro on windows platform with sample code.

jeremy-visionaid commented 7 months ago

Just to note here from #12739 that the Page.Loaded event can be hooked instead as a workaround

Mark-NC001 commented 2 months ago

This is quite a big issue for me, as I have Try...Catches in OnAppearing that call DisplayAlert to let the user know of issues.

jeremy-visionaid commented 2 months ago

@Mark-NC001 Coud you queue it on the dispatcher as a workaround? I was able to reorganize to avoid the problem deterministaically via Loaded, but in my initial attempt I found I needed quite a long delay before it worked (maybe 2-3 seconds on the first OnAppearing invocation)

kubaflo commented 2 months ago

Hi, @Mark-NC001 try this as a workaround

    protected override void OnAppearing()
    {
        base.OnAppearing();
        DisplayAlertOnAppearing("Hello","Message","Ok");
    }

    void DisplayAlertOnAppearing(string title, string message, string cancel) 
    {
        Loaded += OnLoaded;
        void OnLoaded(object sender, EventArgs e)
        {
            DisplayAlert(title, message, cancel);
            Loaded -= OnLoaded;
        }
    }
Mark-NC001 commented 2 months ago

@kubaflo and @jeremy-visionaid thanks for the info. In the end I've made a new function that I call from within OnAppearing, waiting until it's done. I'm preparing myself for the many reasons why I shouldn't do this.....!

public static async Task EnsurePageLoaded(Page page, int intervalMilliseconds = 100, int maxWaitMilliseconds = 6000)
{
        if (page == null) throw new ArgumentNullException(nameof(page));

        int maxWaited = 0;

        while (!page.IsLoaded)
        {
            if (maxWaited > maxWaitMilliseconds)
                throw new InvalidOperationException("Waited " + maxWaited + " milliseconds, but page still not loaded!");

            maxWaited += intervalMilliseconds;
            await Task.Delay(intervalMilliseconds);
        }
}

Also, it's not just DisplayAlerts that aren't working - I'm also using dependency injection: Application.Current.MainPage.Handler.MauiContext.Services.GetService() and Handler appears to be null, until the page has loaded.