2016-08-25 15 views
2

ユーザーが検索語を入力できるUIを作成していて、リストには常に提案候補が表示されます。スロットルが遅すぎると結果が破棄されます

私の最初のことは、Rxの原始的なスロットルは完璧な試合だったが、そこに私の半分を得ることができた。

私はUIスレッドではなく非同期的にそれらを取得するので、提案はフェッチするのに時間がかかります。

問題は、ユーザーがスロットル時間スパンをもう一度タイプした場合、結果を破棄/スキップ/スローすることです。例えば

  • 開始時刻とユーザがキーを押した:は0ms
  • スロットルが100ミリ秒に設定されています。
  • フェッチには200msかかります。
  • ユーザーがスロットルで今すぐ別のキー

を押し150msの時にフェッチ最初はまだ先に行くAN GUI候補リストに移入されます。 私が学びたいのは、もはや最初のフェッチをそれ以上関連しないように取り消すことができることです。 2番目のキーを押すだけで、guiへの更新が開始されます。ここで

は、私はあなたが正しく何をしたい理解していれば、これは非常に単純な方法で行うことができます

public IEnumerable<usp_getOpdrachtgevers_Result> Results { get; set; } // [Reactive] pu 

public SearchOpdrachtgeverVM() 
{ 

    this.WhenAnyValue(x => x.FirstName, 
         x => x.LastName 
     ) 
     .Throttle(TimeSpan.FromMilliseconds(200)) 
     .Subscribe(async vm => Results = await PopulateGrid()); 
} 

private async Task<IEnumerable<usp_getOpdrachtgevers_Result>> PopulateGrid() 
{ 

    return await Task.Run(
      () => _opdrachtgeversCache 
         .Where(x => 
           x.vNaam.Contains(FirstName) 
           && x.vLastName.Contains(LastName) 
         ) 

      ); 

} 

答えて

0

(私はReactiveUIを使用しますが、Qは受信についてです)私は

を試みたものですし、コードを少しリファクタリングすればきれいにしてください。

まず、最初の名前と最後の名前をトリガとしてオブザーバブルにします。下のコードでは、私は主題を使用しましたが、静的なObservableメソッドを使用してオブザーバブルに変換することができる方が良いです。例えばObservable.FromEvent

次に、コードを回して結果を観測可能なものに取り込みます。下のコードでは、Observable.Createを使用してIEnumerable<string>のストリームを返しました。

最後に、Switch演算子を使用して、新しいGetResults呼び出しをサブスクライブし、以前のGetResults呼び出しをキャンセルすることができます。

は複雑に聞こえるが、コードは非常に単純です:

private Subject<string> _firstName = new Subject<string>(); 
private Subject<string> _lastName = new Subject<string>(); 

private Task<IEnumerable<string>> FetchResults(string firstName, string lastName, CancellationToken cancellationToken) 
{ 
    // Fetch the results, respecting the cancellation token at the earliest opportunity 
    return Task.FromResult(Enumerable.Empty<string>()); 
} 

private IObservable<IEnumerable<string>> GetResults(string firstName, string lastName) 
{ 
    return Observable.Create<IEnumerable<string>>(
     async observer => 
     { 
      // Use a cancellation disposable to provide a cancellation token the the asynchronous method 
      // When the subscription to this observable is disposed, the cancellation token will be cancelled. 
      CancellationDisposable disposable = new CancellationDisposable(); 

      IEnumerable<string> results = await FetchResults(firstName, lastName, disposable.Token); 

      if (!disposable.IsDisposed) 
      { 
       observer.OnNext(results); 
       observer.OnCompleted(); 
      } 

      return disposable; 
     } 
    ); 
} 

private void UpdateGrid(IEnumerable<string> results) 
{ 
    // Do whatever 
} 

private IDisposable ShouldUpdateGridWhenFirstOrLastNameChanges() 
{ 
    return Observable 
     // Whenever the first or last name changes, create a tuple of the first and last name 
     .CombineLatest(_firstName, _lastName, (firstName, lastName) => new { FirstName = firstName, LastName = lastName }) 
     // Throttle these tuples so we only get a value after it has settled for 100ms 
     .Throttle(TimeSpan.FromMilliseconds(100)) 
     // Select the results as an observable 
     .Select(tuple => GetResults(tuple.FirstName, tuple.LastName)) 
     // Subscribe to the new results and cancel any previous subscription 
     .Switch() 
     // Use the new results to update the grid 
     .Subscribe(UpdateGrid); 
} 

クイックヒント:あなたは本当にTestSchedulerを使用してスロットル効果的にあなたができるように、ユニットテスト、このコードに明示的なスケジューラを渡す必要があります。

希望します。

+0

'WhenAnyValue'メソッドは、あなたが提案しているすべての対象コードのReactiveUIショートハンドです。 – Shlomo

+0

こんにちは@bibbs。 Shlomoが指摘したように、私はReactiveUIを使って配管の一部を排除しています。私は本当にそれを書くことによってあなたの答えをありがとう!スケジューラについてのヒントは、私もあまりよく見ていくものです。 – buckley

+0

これはテキストブックの例であるようです。http://www.introtorx.com/content/v1.0.10621.0/12_CombiningSequences.html#Switch – buckley

3

あなたが観察可能にあなたの非同期タスクを有効にした場合、これはSwitchのための古典的な使用のようになります。ユーザーが入力している間

this.WhenAnyValue(x => x.FirstName, 
        x => x.LastName 
    ) 
    .Throttle(TimeSpan.FromMilliseconds(100)) 
    .Select(l => PopulateGrid().ToObservable()) 
    .Switch() 
    .Subscribe(vm => Results = vm); 

Throttleは、通話を抑制するために使用する必要があります。そのようにTimeSpanを調整してください。

+0

ああスイッチはい。それは私がそれについて読んだときに役立つかもしれないプリミティブです、そして、これは収まるかもしれません。私は明日行くつもりです。 switchの定義:観測可能なシーケンスの観測可能なシーケンスを、観測可能なシーケンスに変換して、最新の観測可能なシーケンスからの値のみを生成します。 – buckley

関連する問題