C# 取消并重新执行ReactiveCommand

C# 取消并重新执行ReactiveCommand,c#,reactiveui,C#,Reactiveui,我正在努力解决一个我觉得非常简单的ReactiveUI用例,它必须有“开箱即用”的支持。但是我找不到它 该场景是具有以下功能的基本搜索界面: 用户在其中输入搜索文本的搜索字符串文本框 显示结果的结果文本框 显示正在进行搜索的指示器 搜索应如下所示: 搜索字符串文本框被限制,以便在500毫秒后 处于非活动状态时,将启动搜索操作 每次启动新搜索时,应取消任何正在进行的搜索操作 基本上,我试图扩展“引人注目的示例”,在启动新命令之前取消当前正在执行的命令 看起来很容易?是的,但我不能用Reac

我正在努力解决一个我觉得非常简单的ReactiveUI用例,它必须有“开箱即用”的支持。但是我找不到它

该场景是具有以下功能的基本搜索界面:

  • 用户在其中输入搜索文本的搜索字符串文本框
  • 显示结果的结果文本框
  • 显示正在进行搜索的指示器
搜索应如下所示:

  • 搜索字符串文本框被限制,以便在500毫秒后 处于非活动状态时,将启动搜索操作
  • 每次启动新搜索时,应取消任何正在进行的搜索操作
基本上,我试图扩展“引人注目的示例”,在启动新命令之前取消当前正在执行的命令

看起来很容易?是的,但我不能用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的状态如何,我都会启动一个新的搜索。这使得执行
不可靠,因为它假定命令是串行操作的。我不能使用
InvokeCommand
而不是
Execute
,因为在搜索过程中不会启动新的搜索


我目前有一个没有
ReactiveCommand
的工作解决方案。但是我有一种强烈的感觉,这个简单的用例应该使用
ReactiveCommand
以一种简单的方式得到支持。我遗漏了什么?

AFAICT Rx7不能真正处理这种重叠执行。所有的信息最终都会通过,但不会让你的iExecution保持一致。Rx6使用了飞行中的计数器,因此可以处理重叠的执行,但Rx7将其简化了。最有可能的性能和可靠性(但我只是猜测)。因为任务不会立即取消,第一个命令将在第二个命令启动后完成,这将导致ISExecution从true切换到false再切换到true。但是,随着消息的跟进,从假到真再到假的中间过渡会立即发生。我知道你说你有一个非反应性命令在工作,但我认为这是一个版本,它可以通过等待第一个命令完成或完成取消来处理反应性命令。等待任务真正取消的一个好处是,你可以确信你没有两只手在饼干罐中:-),这在你的情况下可能并不重要,但在某些情况下可能很好

//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);
//立即触发事件,以便更快地取消搜索
var searchEntered=this.whenyValue(vm=>vm.SearchString)
.Where(x=>!String.IsNullOrWhiteSpace(x))
.Publish()
.RefCount();
ReactiveCommand searchCmd=ReactiveCommand.CreateFromObservable(
(searchString)=>Observable.StartAsync(ct=>CancelableSearch(searchString,ct))
.TakeUntil(输入));
//如果触发,请等待IsExecuting转换回false,然后再次触发命令
var searchTrigger=
搜索输入
.节气门(时间跨度从毫秒(500))
.Select(searchString=>searchCmd.IsExecuting.Where(e=>!e).Take(1).Select(=>searchString))
.Publish()
.RefCount();
_正在搜索=
searchCmd.IsExecuting
.ToProperty(这个,vm=>vm.IsSearching);
搜索触发器
.Switch()
.InvokeCommand(searchCmd);

回答得很好。谢谢序列化操作确实是一种选择。但由于取消可能需要一段时间才能完成,我宁愿“忘记”正在进行的操作,立即开始新的操作。