8

ViewModels が INotifyPropertyChanged イベントを介して Views を更新する MVVM では、async/await の優れた機能の余地があまりないようです。呼び出し元のキャプチャされた同期コンテキストで継続を実行します。

では、この場合、実際に最新の UI ベースのアプリで async/await の機能を使用するのは誰でしょうか? このコンテキストでは、「誰が」は、MVC バリエーションなどのパターンを意味する場合もあります。

TAPの良い使い方として次のことが考えられます。

ViewModel.Age
{
  set {
    await Model.SetAge(value);
    NotifyPropertyChanged("Age");
  }
}

ただし、キャプチャされた syncContext でこれを実行しても、実際にはあまり役に立ちません。実際、代わりにこれらすべてをモデルに入れることができます。

Model.Age
{
  set {
    await SetAge(value);
    NotifyPropertyChanged("Age");
  }
}

ここで、syncContext がキャプチャーされないようにしたいと考えています。

4

1 に答える 1

30

実際にINotifyPropertyChanged.PropertyChangedは、UI同期コンテキストで発生したことがデータバインディングに必要です。

async/プロパティ(現在の状態を表し、常に同期している)とコマンド(アクションを表し、同期または非同期の場合があります)をawait区別するように強制します。プロパティのゲッターとセッターはできません。そのため、「非同期セット」を使用したサンプルコードは可能なアプローチではありません。async

async非同期コマンドを有効にします。コマンドバインディングを使用して、ルーティングされたコマンドを非同期的に処理したり、asyncデリゲートをに渡しDelegateCommandたり、独自のICommand実装を使用したりできます。どちらの方法でも、async voidコマンドイベントハンドラーができあがります。

現実的な例は、VMプロパティでMプロパティをメモリ内に設定SaveCommandし、asyncハンドラーを使用することです。コマンドの進行中にUIが適切に応答できるように(通常は少なくともreturnを発生させる)、ハンドラーが追加のVMプロパティ(または他のハンドラーと共有される共通のasyncプロパティ)と対話するのが一般的です。SaveInProgressBusyasyncCanExecutefalse

したがって、asyncハンドラーは次のようになります。

private async void SaveCommandExecute()
{
  try
  {
    // Set VM property; updates View appropriately.
    Busy = true;

    // Do the actual saving asynchronously.
    await Model.SaveAsync();
  }
  catch (Exception ex)
  {
    // Update the VM with error information.
    Error = ex.Message;
  }
  finally
  {
    // Let the VM know we're done.
    Busy = false;
  }
}

private void SaveCommandCanExecute()
{
  return !Busy;
}

VMプロパティ(ErrorおよびBusy)は、キャプチャされたUI同期コンテキストで更新されることに注意してください。


これは、asyncMVVMの中心的な概念を示しています。コマンドはである可能性がありますasyncが、プロパティ(などBusy)は常に現在の状態を表します。

既存のMVVMアプリに追加する場合はasync、ビジネスを示すいくつかの追加のプロパティがあり、場合によっては更新の進行状況(完了率など)も表示されます。アプリケーションによっては、同時に複数の非同期操作を許可する場合があります。この情報をビューに追加するための良い方法を考える必要があります。asyncこれはMVVMアプリの中で最も難しい部分だと思います。

于 2012-11-09T15:05:44.620 に答える