如何在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.Run
在async
代码中是首选。
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; }