我熟悉使用Device.BeginInvokeOnMainThread更新UI线程上的UI元素的规则,但我有一个操作需要在实际上是任务的UI线程上运行。
例如,XLabs.Forms.Mvvm上的Push / PopAsync方法似乎在iOS上表现不正确,除非在UI线程上调用它们。在Acr.UserDialogs库中还有另一个用于显示toast等的例子。
我知道创建一个Action异步基本上是创建一个异步void lambda,并且在异常的情况下冒着创建死锁的风险,显然我不希望这种情况发生。
是否有人在UI线程上执行异步操作的解决方法并不涉及将操作标记为异步?
答案 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);