Xamarin.Forms - BeginInvokeOnMainThread用于异步操作

时间:2016-09-24 06:13:06

标签: c# xamarin async-await xamarin.forms

我熟悉使用Device.BeginInvokeOnMainThread更新UI线程上的UI元素的规则,但我有一个操作需要在实际上是任务的UI线程上运行。

例如,XLabs.Forms.Mvvm上的Push / PopAsync方法似乎在iOS上表现不正确,除非在UI线程上调用它们。在Acr.UserDialogs库中还有另一个用于显示toast等的例子。

我知道创建一个Action异步基本上是创建一个异步void lambda,并且在异常的情况下冒着创建死锁的风险,显然我不希望这种情况发生。

是否有人在UI线程上执行异步操作的解决方法并不涉及将操作标记为异步?

3 个答案:

答案 0 :(得分:6)

请确保您在行动中处理异常并且您应该没事。当您处理异常时,会出现您所描述的问题。下面是从主线程运行异步方法的一个非常简单的示例。

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());
}

答案 1 :(得分:4)

如果有人想要等待必须在主线程上执行的操作结束,请暂停此处

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;
    }
}

答案 2 :(得分:2)

Xamarin.Forms 4.1 起,现在有了一种助手方法,可以在主线程上运行任务并等待它们。

await Device.InvokeOnMainThreadAsync(SomeAsyncMethod);

存在一些应涵盖大多数情况的重载:

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);

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