Xamarin.Forms - BeginInvokeOnMainThread for an async Action

后端 未结 3 1921
我寻月下人不归
我寻月下人不归 2021-01-19 01:02

I am familiar with the rules about updating UI elements on the UI thread using the Device.BeginInvokeOnMainThread, however I have an operation that needs to be run on the UI

相关标签:
3条回答
  • 2021-01-19 01:21

    Just make sure you handle exceptions in your Action and you should be fine. The problem you described occurs when you don't handle the exceptions. Below is a very simple example of running an async method from the main thread.

    private void Test()
    {
        Device.BeginInvokeOnMainThread(SomeMethod);
    }
    
    private async void SomeMethod()
    {
        try
        {
            await SomeAsyncMethod();
        }
        catch (Exception e) // handle whatever exceptions you expect
        {
            //Handle exceptions
        }
    }
    
    private async Task SomeAsyncMethod()
    {
        await Navigation.PushModalAsync(new ContentPage());
    }
    
    0 讨论(0)
  • 2021-01-19 01:23

    Since Xamarin.Forms 4.2 there is now a helper method to run tasks on the main thread and await them.

    await Device.InvokeOnMainThreadAsync(SomeAsyncMethod);
    

    Several overloads exist that should cover most scenarios:

    System.Threading.Tasks.Task InvokeOnMainThreadAsync (System.Action action);
    System.Threading.Tasks.Task InvokeOnMainThreadAsync (System.Func<System.Threading.Tasks.Task> funcTask);
    System.Threading.Tasks.Task<T> InvokeOnMainThreadAsync<T> (System.Func<System.Threading.Tasks.Task<T>> funcTask);
    System.Threading.Tasks.Task<T> InvokeOnMainThreadAsync<T> (System.Func<T> func);
    

    Related PR: https://github.com/xamarin/Xamarin.Forms/pull/5028

    NOTE: the PR had some bug that was fixed in v4.2, so don't use this in v4.1.

    0 讨论(0)
  • 2021-01-19 01:27

    Dropping this here in case someone wants to await the end of an action which has to be executed on the main thread

    public static class DeviceHelper
    {
        public static Task RunOnMainThreadAsync(Action action)
        {
            var tcs = new TaskCompletionSource<object>();
            Device.BeginInvokeOnMainThread(
                () =>
                {
                    try
                    {
                        action();
                        tcs.SetResult(null);
                    }
                    catch (Exception e)
                    {
                        tcs.SetException(e);
                    }
                });
    
            return tcs.Task;
        }
    
        public static Task RunOnMainThreadAsync(Task action)
        {
            var tcs = new TaskCompletionSource<object>();
            Device.BeginInvokeOnMainThread(
                async () =>
                {
                    try
                    {
                        await action;
                        tcs.SetResult(null);
                    }
                    catch (Exception e)
                    {
                        tcs.SetException(e);
                    }
                });
    
            return tcs.Task;
        }
    }
    
    0 讨论(0)
提交回复
热议问题