Quick Links

Is it possible to wait for Device.BeginInvokeOnMainThread code to finish

In my code I have a task called "ShowMessageBoxAsync". I want to use this code to show (and await) the DisplayAlert to the user and return the result. Like this: var messageBoxResult = await View.ShowMessageBoxAsync("This is an error");

Before I added the Device.BeginInvokeOnMainThread, the task gave me an Exception that it wasn't running on the main/UI thread. So after adding BeginInvokeOnMainThread, it started to work without exceptions. The problem, however, is that the code goes directly to the result, without waiting for the result of the "await DisplayAlert".

Is it possible return the value of "result" only after the Device.BeginInvokeOnMainThread code finishes?

I wrapped the DisplayAlert in a new task and tcs gets signaled as soon as there is a result from the DisplayAlert. The problem is that it still goes directly to the result, without waiting for the user input on the DisplayAlert.. This is how it looks like now:

From what I understand is that tcs.SetResult(result); blocks the UI thread. But is there any possibility in the current construction of the code to show a Dialog (without blocking the UI) and only proceed as soon as the user clicks Yes / No?

Or can this only be solved by splitting it up (for example through a MessageCenter)?

P.S.: BeginInvokeOnMainThread is added in Btn_Clicked function in order to make both alerts run properly. Another option would be adding BeginInvokeOnMainThread for each of them, but, why duplicate code?

@KSTeixeira Many thanks for your response, it's very helpful In order not to break the rest of the project code, the GetResult method must unfortunately always return a bool. This bool result will be based on the result of the DisplayAlert. I tried doing it on this way:

public bool GetResult()
{
bool result = false;
Device.BeginInvokeOnMainThread(async () =>
{
result = await this.GetResultFromAlert("Error");
});
return result; // this should return when there is a result from the DisplayAlert
}

I know what @JohnHardman said about calling Device.BeginInvokeOnMainThread, so this code directly goes to "return result" (without awaiting the DisplayAlert). Do you know if there's a workaround to keep this code in the bool GetResult method, but also await the DisplayAlert result and then return this result?

I understand that sometimes we face challenges like this and we "suffer" to release something working, but we MUST do everything we can to keep it consistent and correct, otherwise, you can have even more issues in the future.

I'm sorry not being able to help you solving your problem, but consider my opinion of refactoring your code. Refactoring is cool man

@Richard0 said:
I know what @JohnHardman said about calling Device.BeginInvokeOnMainThread, so this code directly goes to "return result" (without awaiting the DisplayAlert). Do you know if there's a workaround to keep this code in the bool GetResult method, but also await the DisplayAlert result and then return this result?

Switching from procedural code to event-driven code involves a change of mindset. In this particular scenario, rather than asking how to make something happen and return Task<bool>, instead consider what you want to happen if the user hits "OK" and what you want to happen if the user hits "Cancel". It's then a case of wiring up the result of DisplayAlert to those difference outcomes, normally without the Task<bool> return (or in the scenario where there is a requirement to implement an interface returning a dummy value). Using MessagingCenter is one way of doing that wiring, although not the only way.

I don't have the solution yet, but I've learned new things about async programming. I am going to see how I can refactor the code with your advice. And once I've found a good way, I'll post it here, so that someone else might also benefit from it