我想在我的Windows Phone 8 MVVM项目中使用async/await,并且我正在努力寻找一种好的方法来使用这个API实现我的ICommands。
我已经阅读了一些关于此主题的文章,其中我看到了下面这篇来自MSDN的文章,它指出我必须避免使用async voids,因为很难捕获未处理的异常:
http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
在另一个问题中,我提到了这个问题,有人也说我不应该使用async voids,除非是用于事件。
但问题在于,我在互联网上找到的所有示例都使用async voids。 我找到的这两篇文章就是例子: http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ 和 http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/ 最后一个是使用async/await实现ICommand的一个例子,但它也使用了async voids。 我正在尝试想出一个解决方案,所以我写了这个基于RelayCommand的ICommand实现:
但问题在于,我在互联网上找到的所有示例都使用async voids。 我找到的这两篇文章就是例子: http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/ 和 http://blog.mycupof.net/2012/08/23/mvvm-asyncdelegatecommand-what-asyncawait-can-do-for-uidevelopment/ 最后一个是使用async/await实现ICommand的一个例子,但它也使用了async voids。 我正在尝试想出一个解决方案,所以我写了这个基于RelayCommand的ICommand实现:
public delegate Task AsyncAction();
public class RelayCommandAsync : ICommand
{
private AsyncAction _handler;
public RelayCommandAsync(AsyncAction handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
ExecuteAsync();
}
private Task ExecuteAsync()
{
return _handler();
}
}
我正在尝试像这样使用它: 在构造函数中:
saveCommand = new RelayCommandAsync(SaveSourceAsync);
然后:
private async Task SaveSourceAsync()
{
await Task.Run(() => { Save(); });
}
private void Save()
{
// Slow operation
}
问题在于我对这种实现方式以及其他实现方式都不感到舒适,因为我不知道哪种是最好和最优的。
有人能够指导我如何使用它吗,最好是用MVVM模式?
SimpleAsyncCommand
,看起来它符合我的需求,我只想知道:我的ExecuteAsync
方法将要调用的方法将在UI上下文中运行,我需要在这个方法中使用await Task.Run
,对吗?这样做会丢失任何异常吗?如果不会,我想我会使用你的库! - Eric.MICommand
的异常将在WP UI上引发,因此它们将被发送到Application.UnhandledException
。ExecuteAsync
将在UI线程上执行(因此您的async
委托将在UI线程上开始运行)。如果您需要为该命令执行阻塞工作,则可以使用await Task.Run
;如果您有异步工作要做,则不需要Task.Run
,只需使用await
即可。实际上,它还不是我的库的一部分;您现在只需复制源代码。 - Stephen ClearyTask.Run
了吗? 比如,如果我将保存数据的代码放在返回Task
的方法中并等待它,那么它不会阻塞UI吗?Task.Run
只用于像访问Web服务这样真正密集的操作吗?如果是这样的话,那太好了!哈哈哈 =) - Eric.MSaveChangesAsync
或其他内容,则可以直接await
它,无需使用Task.Run
。Web服务具有更好的异步支持,例如,HttpClient
具有GetAsync
等功能,您可以直接await
。Task.Run
实际上是用于CPU密集型(而非I/O绑定)代码,但如果需要,它也可以用于使同步API看起来异步。 - Stephen Cleary