我如何在mvvmcross视图模型中使用异步
本文关键字:异步 模型 视图 mvvmcross | 更新日期: 2023-09-27 18:19:11
我在mvvmcross视图模型中有一个长时间运行的过程,并希望使其异步(http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx)。
async关键字目前在Xamarin的测试版通道中得到支持。
下面是我目前如何实现异步的一个例子。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
,这是单元可测试的,并且可以从代码的其他部分使用:
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中的一种常见方法。
I did change Task.Factory.StartNew
to Task.Run
;在async
代码中首选Task.Run
,原因由Stephen Toub描述。
MvvmCross现在有MvxAsyncCommand
(见GitHub提交)。
所以我们不这样做
public ICommand MyCommand
{
get
{
return new MvxCommand(async () => await DoMyCommand());
}
}
你可以这样做
public ICommand MyCommand
{
get
{
return new MvxAsyncCommand(DoMyCommand);
}
}
看起来很好,除了我将在等待周围添加一个try catch finally。
public async void DoMyCommand()
{
IsBusy = true;
try{
await Task.Factory.StartNew(() =>
{
_myService.LongRunningProcess();
});
}catch{
//Log Exception
}finally{
IsBusy = false;
}
}
进一步,我有一个例子在我的博客上使用MvxCommand与async。与您的示例非常相似http://deapsquatter.blogspot.com/2013/03/updating-my-mobile-apps-for-async.html
你也可以使用 methodbbinding 插件来避免模板代码(命令),直接将你的UI绑定到async方法。
此外,如果您使用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"。
另一方面,与其使用await Task.Factory.StartNew()
,为什么不让_myService.LongRunningProcess
异步?这会更好看:
public async Task DoSomething()
{
IsBusy = true;
await _myService.LongRunningProcess();
IsBusy = false;
}