0

MVVM パターンを使用した私の WPF アプリケーションは、基本的に次のことを実行します。

  • ボタン ビューは、ビュー モデルのコマンドにバインドします。--> チェック!
  • コマンド イン ビュー モデルは、オブジェクトのリストを Web サービスに非同期的にクエリして、CProjectオブジェクトをProjectListプロパティに配置します。--> チェック!

これは、このように見えます...

ビュー モデルでのコマンド:

proxy = new SomeService();
proxy.GetProjectList(GetProjectListCallback, username, password);

ビュー モデルでのコールバック:

private void GetProjectListCallback(object sender, GetProjectListCompletedEventArgs e) {
  this.ProjectList = e.Result;
}

SomeServiceインターフェイスを実装しますISomeService

public void GetProjectList(EventHandler<GetProjectListCompletedEventArgs> callback, string username, string password) {
  service.GetProjectListCompleted += callback;
  service.GetProjectListAsync(username, password);
}

これまでのところ、これはうまく機能します。ただし、ビューモデルが次のようなもののみを呼び出すように、このコールバックをサービス自体に移動したいと思います。

proxy = new SomeService();
this.ProjectList = proxy.GetProjectList(username, password);

e.Resultしかし、コールバックをサービスに移動するときに、呼び出し元のビュー モデルに戻るにはどうすればよいでしょうか? またはTask、より良いアイデアを使用しますか?

4

2 に答える 2

1

残念ながら、そのような非同期操作から値を返すことはできません。スレッドが完了するのを待つためにそのスレッドをブロックする必要があります。結果が利用可能になったときに実行するには、常に何らかのコールバックまたは継続が必要です。C# 5 では、async/await構文がそのための多くの配管を行いますが、最終的にはTask.ContinueWith.

WCF が提供する非同期操作に満足しているのであれば、TPL を使用せず、C# 5 コンパイラを使用できない場合でも、現在使用しているパターンは適切なものに思えます。

私自身のコードでは、以前に少し異なる方法でビルドしました。スレッドプールのスレッドから呼び出される同期 WCF 操作を使用し、同時実行性とコールバックを Reactive Extensions によって管理します。ただし、効果はほとんど同じで、必要な構文と概念モデルの種類に依存します。Rx を使用することは、多くの Rx キットを使用して既に構築されているアプリケーションに自然に適合します。これは、IObservableデータがどのように移動するかという同じドメインに私たちをとどまらせるためです。

于 2013-02-01T11:13:10.200 に答える
1

最も簡単な方法は、VS2012 で WCF サービス プロキシを再作成することです。これにより、非同期メソッドのシグネチャが次のように変更されます。

Task<MyProjectList> GetProjectListAsync(string username, string password);

コマンドは次のようになります。

proxy = new SomeService();
this.ProjectList = await proxy.GetProjectListAsync(username, password);

WCF サービス プロキシを再作成したくない場合 (すべてのメソッド シグネチャが更新されます)、/メソッド次のようにラップできます。Begin*End*

public static Task<MyProjectList> GetProjectListTaskAsync(this SomeService @this, string username, string password)
{
  return Task<MyProjectList>.Factory.FromAsync(@this.BeginGetProjectList, @this.EndProjectList, username, password, null);
}

私のブログには、この種のラッピングの完全な例があります。

または既存の*Async/*Completedメンバーなど:

public static Task<MyProjectList> GetProjectListTaskAsync(this SomeService @this, string username, string password)
{
  var tcs = new TaskCompletionSource<MyProjectList>();
  EventHandler<GetProjectListCompletedEventArgs> callback = null;
  callback = args =>
  {
    @this.GetProjectListCompleted -= callback;
    if (args.Cancelled) tcs.TrySetCanceled();
    else if (args.Error != null) tcs.TrySetException(args.Error);
    else tcs.TrySetResult(args.Result);
  };
  @this.GetProjectListCompleted += callback;
  @this.GetProjectListAsync(username, password);
}
于 2013-02-01T14:24:14.737 に答える