8

ビューモデルの1つにスロットル動作を実装しようとしています。これはSilverlightアプリケーションですが、特に重要ではないと思います。

次の3つのプロパティを持つクラスについて考えてみます。

  • プロパティ1
  • プロパティ2
  • プロパティ3

これらのプロパティの1つが更新されるたびに、更新が必要です。

private void Refresh()
{
    //Call out to the server, do something when it comes back
}

私の目標は次のとおりです。

  • 更新が進行中の場合は、サーバーへの呼び出しをキャンセルして、新しいリクエストを発行するのが理想的です。
  • プロパティが変更された場合は、追加の変更を待つための小さな時間枠(おそらく0.1秒)を残す必要があります。このように、複数のプロパティが急速に(たとえば、プログラムで)変更された場合でも、サーバーにリクエストをスパム送信することはありません。その0.1秒のウィンドウは、変更のたびにリセットしても問題ありませんが、必須ではありません。

重要な場合は、サーバー呼び出しにChannelFactory実装を使用しています。

これを実現するためにどのようなパターンを使用できますか?これはリアクティブエクステンションが私を助けることができるものですか?

編集:

ポールの答えを正しいものとしてマークする。ReactiveUIは現在silverlight5に対しては機能しませんが、Rxを使用して問題を解決するためのアプローチ/構成手順の概要を明確に示しています。

4

1 に答える 1

6

ReactiveUIを使用してこれを行う方法は次のとおりです。

IObservable<TheData> FetchNewData() 
{
    // TODO: Implement me
}

this.WhenAny(x => x.Property1, x => x.Property2, x => x.Property3, (x,y,z) => Unit.Default)
    .Throttle(TimeSpan.FromMilliseconds(200), RxApp.DeferredScheduler)
    .Select(x => FetchNewData())
    .Switch()    // We only care about the req corresp. to latest values of Prop1-3
    .ToProperty(this, x => x.Data);

更新:これは、一度に1つしか実行されないことを保証する方法ですが、順序が狂う結果が生じる可能性があることに注意してください。

this.WhenAny(x => x.Property1, x => x.Property2, x => x.Property3, (x,y,z) => Unit.Default)
    .Throttle(TimeSpan.FromMilliseconds(200), RxApp.DeferredScheduler)
    .Select(_ => Observable.Defer(() => FetchNewData()))
    .Merge(1)
    .ToProperty(this, x => x.Data);

プロパティが変更され続けると、発行する古いリクエストのキューが作成されるため、説明する動作は実際には望ましくない可能性があります。「BufferingSwitch()」演算子のようなものを作成すると、これを最適化できます。変更がないことが確実になるまで結果を返しませんでした-それは実際に書くのがクールでしょう。

物語の教訓、AsyncIsComplicated™:)

于 2012-06-15T18:46:34.633 に答える