0
votes

I have some problems in my Xamarin.Forms app related to invoking async method in the page constructor so when I test something trying to figure out the reason I just realized DisplayAlert method does not even work in the page constructor so I am wondering why is that happening?

Here is my code:

    public MainPage ()
    {
        InitializeComponent ();
        DisplayAlert("An alert", "Why I don't show up?", "Ok");
    }

and I also tried to call async method that has DisplayAlert method but didn't work too, here is the code:

    public MainPage ()
    {
        InitializeComponent ();
        Async_Function_Has_DisplayAlert();
    }
    async void Async_Function_Has_DisplayAlert()
    {
        // I tried both and neither of them worked
        await DisplayAlert("An alert", "Why I don't show up?", "Ok");
        await Task.Run(()=> DisplayAlert("An alert", "Why I don't show up?", "Ok"));
    }

So can someone explain why that is happening please?

3
Can you check if my solutions help? - Amadeu Antunes
the constructor runs before the UI of the page has been built. Use OnAppearing() instead - Jason

3 Answers

0
votes

Normally, you should not call an awaitable method like DisplayAlert() from the constructor. What you can do is have a method that returns void (still not best practice) and call that method from your constructor.

Tweaking my recommendation after trying it out. I used Device.Timer to delay the alert. I think some components have not finished loading (in this case, the DisplayAlert) before trying to call it.

public MainPage()
    {
        InitializeComponent();
        Device.StartTimer(TimeSpan.FromSeconds(4), () =>
        {
            ShowMessage();
            return false; // True = Repeat again, False = Stop the timer
        });
    }
    public async void ShowMessage()
    {

        await DisplayAlert("Alert", "I show here", "OK");

    }

enter image description here

0
votes

There seems to be a misconception on what is happening in the constructor. The constructor simply creates a new Page class.

CustomMainPage mainpage = new CustomMainPage();
(App.Current as App).MainPage = new NavigationPage(mainpage);

So before we add the mainpage class to the NavigationPage, all that has happened is that the CustomMainPage class was initialized and is ready to be inserted into an appropriate container. However after creating the new page, there is no actual UI on the screen, yet. For instance, the mainpage object wouldn't have width or height set, no layout has been done, etc... If you run a UI related task, such as presenting an Alert, there isn't simply any foundation for it there, which could do anything resonable.

Of course you could already set members of the mainpage, such as labels or buttons to certain values, colors, styles or whatever you want, from within the constructor, but these wouldn't do anything at that point of time. All of those values will be taken into account when the page is being layouted and presented but none of that will happen in the constructor.

However, back to your problem: You seemingly want to inform the user that something has gone wrong during the initialization.

I see two ways of adressing that issue:

  1. Check the preconditions on the page or within the code before initializing your view and present the Alert from the page or class, which is initializing your page.
  2. create a private variable in your page class, which you will set from within your page constructor if something goes wrong. This could be a simple bool flag, a string containing an error message, an enum or whatever suits your needs. Then override the OnAppearing() method, check that flag you set earlier and call DisplayAlert depending on the flag's value.

If you want any interactivity on your page, then you should consider Jason's comment to your question and implement it within OnAppearing, because this method will be called once your page has been fully layouted and is being presented on your screen.

0
votes

Sample code for Jason's recommendation

public async void ShowMessage()
    {
        await DisplayAlert("Alert", "I show here", "OK");
    }
    protected override void OnAppearing()
    {
        ShowMessage();
    }