2013-05-31 8 views
6

私はWindows Phone 8 MVVMプロジェクトでasync/awaitを使いたいのですが、私はこのapiを使ってICommandsを実装する良い方法を見つけるのに苦労しています。 私はこの件についていくつかの記事を読んできましたが、私は非同期のボイドを避けなければならないという下記のMSDNのこの記事にぶつかっています: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx 別の質問で、私は非同期ボイドを使用すべきではないと言った人もいました。イベントでない限り。async/MVVMで待たずにvoidメソッド

しかし、問題は、私がインターネット上で見つけることができるすべての例が非同期ボイドを使用していることです。私が見つけた この2品は例です: 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/

最後のものは/待って非同期を使用してのICommandの実装ですが、それはまた、非同期空隙を使用しています。 私はこのための解決策を考え出すしようとしているので、私は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を使用するいくつかの光を与えることができますか?参照記事で

答えて

21

、私はそれがガイドライン「async voidを避ける」から例外と考えられるのでICommand.Executeは、実質的にイベントハンドラであることを指摘しました:あなたがすべき、

この最初のガイドラインを要約しますprefer async async to void to ...このガイドラインの例外は非同期イベントハンドラであり、voidを返す必要があります。この例外には、文字通りイベントハンドラ(ICommand.Executeの実装など)でない場合でも、論理的にイベントハンドラであるメソッドが含まれます。あなたのICommand実装について

、それは実際にasync voidを使用してないにより欠陥が導入されていますICommand.Execute実装では、その例外を観察せずにTaskを破棄します。実装では、async代理人によって発生した例外は無視されます。

対照的に、リンク先のブログ投稿はasync void ICommand.Executeです。awaitTaskです。例外がUI同期コンテキストに伝播できるようにします。これは、同期ICommand.Executeが例外を発生させたときと同じ動作であるため、この場合は望ましい動作です。

あなたがこの傾向を持っているなら、私はICommandまたは2つを私がAsyncEx libraryの将来の可能性のために書いたことを試してみたいです。 first oneは、あなたが投稿したブログのものと非常によく似た簡単なコマンドです。second oneはキャンセル、進捗報告、およびCanExecuteの自動管理を含むもっと完全な「非同期コマンド」実装です。私はフィードバックをいただければ幸いです。

+0

私はあなたのlibと実装を見ています。 Windows Phone App.xamlで未処理の例外イベントを発生させた場合に例外が発生した場合は、ここに入れたブログ記事のICommand実装で何かを教えてください。 私は後でそれをテストします。 –

+0

私は 'SimpleAsyncCommand'を見ていました。私の目的のために働くように見えます。私は' ExecuteAsync'が呼び出す予定の私のメソッドをUIのコンテキストで実行しています。このメソッド内で 'await Task.Run'を使用してください。このように動作する例外は失われますか?もしそうでなければ、私はあなたのライブラリーを使うつもりだと思う! –

+0

WP UIで 'ICommand'の例外が発生するので、' Application.UnhandledException'に送られます。 'ExecuteAsync'がUIスレッドで実行されます(つまり、' async'デリゲートはUIスレッド上で実行されます)。あなたは 'await Task.Run'コマンドを実行することができます。非同期の作業がある場合は、 'Task.Run'は必要なく、単に' await'を使うことができます。それは実際に私のlibの一部ではありません。今のところソースをコピーするだけです。 –

関連する問題