2013-05-31 25 views
6

我想在我的Windows Phone 8 MVVM項目上使用async/await,並且我正在努力尋找一種使用此API來實現我的ICommands的好方法。 我一直在閱讀關於這個主題的一些文章,我碰到了下面這個來自MSDN的文章,其中說我必須避免異步空洞,因爲它很難捕捉未處理的異常: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx 在另一個問題中,主題,有人也說我不應該使用異步空洞。除非事件發生。異步/等待在MVVM無異常方法

但問題是,我可以在互聯網上找到所有的例子使用異步空洞。 我發現這兩篇文章的例子: 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/

最後一個是用異步/ AWAIT,但它也使用了異步空隙的ICommand的實現。 我試圖想出一個解決方案,所以我寫了這個實現的ICommand的基礎上,RelayCommand:

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?

回答

21

在引用的文章,我也指出,ICommand.Execute實際上是一個事件處理程序,所以它會被認爲是從「避免async void」方針的異常:

總結這第一個原則,你應該更喜歡異步任務異步無效...此指南的異常是異步事件處理程序,它必須返回void。此異常包括邏輯上的事件處理程序,即使它們不是字面上的事件處理程序(例如,ICommand.Execute實現)。

關於你ICommand實現,它實際上介紹了利用async void通過一個缺陷:ICommand.Execute實現將丟棄Task不遵守它的例外。因此,實施將忽略async委託人提出的任何例外情況。

相比之下,您鏈接到的博客文章有async void ICommand.Execute其中awaitTask,允許異常傳播到UI同步上下文。其中 - 在這種情況下 - 是期望的行爲,因爲它與您在同步ICommand.Execute引發異常時得到的行爲相同。

如果您有任何傾向,我想請您嘗試一下ICommand或兩個我爲未來寫入我的AsyncEx library而寫的內容。 first one是一個非常類似於您發佈的博客中的簡單命令。second one是一個更完整的「異步命令」實現,包括取消,進度報告和CanExecute的自動管理。我會很感激任何反饋。

+0

我正在看你的lib和實現。 那麼告訴我一些事情,如果發生異常,如果在Windows Phone App.xaml中引發未處理的異常事件,用我在這裏放置的博客文章的ICommand實現? 我將在稍後測試它。 –

+0

我正在研究'SimpleAsyncCommand',看起來像它的工作形式我的目的,我只想知道:我的ExecuteAsync將要調用的方法將在UI上下文中運行,我必須在這個方法中使用'await Task.Run',對吧?我會失去這樣的例外嗎?如果沒有,我想我會用你的lib! –

+0

將在WP UI上引發'ICommand's的異常,所以它們將被髮送到'Application.UnhandledException'。 'ExecuteAsync'將在UI線程上執行(這樣你的'async'委託就會開始在UI線程上運行)。如果您阻止了該命令的工作,則可以使用'await Task.Run';如果你有異步工作要做,你不需要'Task.Run',只需使用'await'。它實際上並不是我的lib的一部分;你現在只需要複製源代碼。 –