如何在mvvmcross视图模型中使用async?

我在mvvmcross viewmodel中有一个长时间运行的进程,并希望将其设置为异步( http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx )。

Xamarin的测试版渠道目前支持async关键字。

下面是我目前如何实现异步的示例。 IsBusy标志可以绑定到UI元素并显示加载消息。

这是正确的方法吗?

public class MyModel: MvxViewModel { private readonly IMyService _myService; private bool _isBusy; public bool IsBusy { get { return _isBusy; } set { _isBusy = value; RaisePropertyChanged(() => IsBusy); ; } } public ICommand MyCommand { get { return new MvxCommand(DoMyCommand); } } public MyModel(IMyService myService) { _myService = myService; } public async void DoMyCommand() { IsBusy = true; await Task.Factory.StartNew(() => { _myService.LongRunningProcess(); }); IsBusy = false; } } 

你应该避免async void 。 当您处理ICommand ,您确实需要使用async void ,但其范围应该最小化。

此修改后的代码将您的操作公开为async Task ,该async Task可unit testing并可从代码的其他部分使用:

 public class MyModel: MvxViewModel { private readonly IMyService _myService; private bool _isBusy; public bool IsBusy { get { return _isBusy; } set { _isBusy = value; RaisePropertyChanged(() => IsBusy); ; } } public ICommand MyCommand { get { return new MvxCommand(async () => await DoMyCommand()); } } public MyModel(IMyService myService) { _myService = myService; } public async Task DoMyCommand() { IsBusy = true; await Task.Run(() => { _myService.LongRunningProcess(); }); IsBusy = false; } } 

你对IsBusy使用很好; 这是异步UI中的一种常见方法。

我确实将Task.Factory.StartNew更改为Task.Run ; 由于Stephen Toub描述的原因, Task.Runasync代码中是首选。

MvvmCross现在有MvxAsyncCommand (参见GitHub 提交 )。

所以不要这样做

 public ICommand MyCommand { get { return new MvxCommand(async () => await DoMyCommand()); } } 

你可以这样做

 public ICommand MyCommand { get { return new MvxAsyncCommand(DoMyCommand); } } 

看起来不错,除非我最后添加一个try catch等待。

  public async void DoMyCommand() { IsBusy = true; try{ await Task.Factory.StartNew(() => { _myService.LongRunningProcess(); }); }catch{ //Log Exception }finally{ IsBusy = false; } } 

我在博客上使用带有异步的MvxCommand进行了更多示例。 非常类似于您的示例http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html

您还可以使用MethodBinding 插件来避免样板代码(命令),并将UI直接绑定到异步方法。

此外,如果您使用Fody PropertyChanged ,您的代码将如下所示:

 [ImplementPropertyChanged] public class MyModel: MvxViewModel { private readonly IMyService _myService; public bool IsBusy { get; set; } public MyModel(IMyService myService) { _myService = myService; } public async Task DoSomething() { IsBusy = true; await Task.Factory.StartNew(() => { _myService.LongRunningProcess(); }); IsBusy = false; } } 

您可以进行绑定:“Click DoSomething”。

另一方面,为什么不使用_myService.LongRunningProcess异步而不是使用await Task.Factory.StartNew() ? 看起来会好得多:

 public async Task DoSomething() { IsBusy = true; await _myService.LongRunningProcess(); IsBusy = false; }