2016-09-24 259 views
3

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

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

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

有没有人有一个解决方案在UI线程上执行异步操作,不涉及将Action标记为异步?

回答

5

只要确保你在你的操作中处理异常,你应该没问题。您描述的问题发生在不处理异常时。下面是从主线程运行异步方法的一个非常简单的例子。

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

删除该在这里如果有人想等待它必须在主线程上执行的动作结束

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