2017-03-08 51 views
2

我很努力地使用ReactiveUI用例,我覺得它很簡單,必須有「開箱即用」的支持。但我找不到它。取消並重新執行ReactiveCommand

的場景是具有這些特徵的基本搜索界面:

  • 其中用戶輸入的搜索文本
  • 其中結果被呈現
  • 示出的指標的結果的TextBox搜索字符串文本框搜索過程中

搜索應該像這樣工作:

  • 搜索字符串TextBox受到限制,因此在不活動500ms後,將啓動搜索操作。
  • 每次啓動新的搜索時,應該取消正在進行的任何搜索操作。

基本上我試圖擴展「強大的例子」來取消當前正在執行的命令,然後開始一個新的命令。

看起來夠簡單嗎?是的,但是我無法使用ReactiveCommand正確使用它。這是我的:

var searchTrigger = this.WhenAnyValue(vm => vm.SearchString) 
    .Throttle(TimeSpan.FromMilliseconds(500)) 
    .Publish().RefCount(); 
var searchCmd = ReactiveCommand.CreateFromObservable(
    () => Observable 
     .StartAsync(ct => CancellableSearch(SearchString, ct)) 
     .TakeUntil(searchTrigger)); 
searchCmd.ToPropertyEx(this, vm => vm.Result); 
searchCmd.IsExecuting.ToPropertyEx(this, vm => vm.IsSearching); 
searchTrigger.Subscribe(_ => searchCmd.Execute(Unit.Default).Subscribe()); 

上述代碼適用於除了searchCmd.IsExecuting以外的所有方面。無論searchCmd.CanExecute的狀態如何,我都會開始新的搜索。這使得IsExecuting不可靠,因爲它假設串行操作的命令。我不能使用InvokeCommand而不是Execute,因爲在搜索過程中新搜索不會啓動。

我目前有一個沒有ReactiveCommand的工作解決方案。但我有強烈的感覺,這個簡單的使用案例應該以直接的方式使用ReactiveCommand來支持。我錯過了什麼?

回答

3

AFAICT Rx7並沒有真正處理這種重疊執行。所有的信息最終都會通過,但不會保證你的IsExecuting始終如一。 Rx6使用了一個在飛行計數器中處理重疊執行,但Rx7簡化了它。最有可能的性能和可靠性(但我只是猜測)。因爲任務不會立即取消,第二個命令開始後第一個命令即將完成,這會導致IsExecuting從true切換到false,從而切換到false。但是,當信息迎頭趕上時,從虛假到真實的中間過渡會立即發生。我知道你說過你有一個非Reactive Command工作,但是這裏有一個我認爲可以通過等待第一個命令完成或完成取消的Reactive Commands。等待任務真正取消的一個好處是,您可以放心,您的餅乾罐中沒有兩隻手:-)這可能無關緊要,但在某些情況下可能會更好。

//Fires an event right away so search is cancelled faster 
var searchEntered = this.WhenAnyValue(vm => vm.SearchString) 
    .Where(x => !String.IsNullOrWhiteSpace(x)) 
    .Publish() 
    .RefCount(); 



ReactiveCommand<string, string> searchCmd = ReactiveCommand.CreateFromObservable<string, string>(
    (searchString) => Observable.StartAsync(ct => CancellableSearch(SearchString, ct)) 
        .TakeUntil(searchEntered)); 

//if triggered wait for IsExecuting to transition back to false before firing command again 
var searchTrigger = 
    searchEntered 
     .Throttle(TimeSpan.FromMilliseconds(500)) 
     .Select(searchString => searchCmd.IsExecuting.Where(e => !e).Take(1).Select(_ => searchString)) 
     .Publish() 
     .RefCount(); 

_IsSearching = 
    searchCmd.IsExecuting 
    .ToProperty(this, vm => vm.IsSearching); 


searchTrigger 
    .Switch() 
    .InvokeCommand(searchCmd); 
+1

很棒的回答。謝謝。序列化操作確實是一種選擇。但由於取消可能需要一段時間才能完成,我寧願只是「忘記」正在進行的操作並立即開始新的操作。 –