c# - 在 ReactiveUI 中取消/忽略 ReactiveAsyncCommand 的结果

标签 c# wpf reactiveui

我有一个 ReactiveAsyncCommand 可以在用户输入文本框时执行搜索,其设置如下:

var results = SearchCommand.RegisterAsyncFunction(term => 
PerformSearch((string)term));

this.ObservableForProperty(x => x.SearchTerm)
.Throttle(TimeSpan.FromMilliseconds(800))
.Select(x => x.Value).DistinctUntilChanged()
.Where(x => !String.IsNullOrWhiteSpace(x))
.InvokeCommand(SearchCommand);

_SearchResults = results.ToProperty(this, x => x.SearchResults);

问题在于搜索功能可能会很慢,因为它需要执行数据库查询并显示过时的结果,我认为这是由于 ReactiveAsyncCommand 直到当前才再次运行异步任务完成。

所以我的问题是,如果不是针对当前搜索词,我该如何取消正在运行的异步任务并重新开始使用当前搜索词,或者完全删除结果。

好像和this discussion的第二部分一样,但我不确定如何将其应用于我的代码,因为我的搜索代码返回 IEnumerable 而不是 IObservable。

请注意 RxUI 4,因为它是一个 .NET 4 应用程序。

更新:PerformSearch 方法

private List<WizardLocationSearchResult> PerformSearch(string searchTerm)
{
var results = new List<WizardLocationSearchResult>();
bool isMatch = false;


if (Regex.IsMatch(searchTerm, _postcodeRegex, RegexOptions.IgnoreCase))
{
    var locationResult = _locationService.GetByPostcode(searchTerm);
    _locationService.DeepLoad(locationResult, true, Data.DeepLoadType.IncludeChildren, typeof(TList<EnterpriseAndHolding>));

    results.AddRange(ProcessLocationSearches(locationResult));
    isMatch = true;
}


if (!isMatch)
{
    var query = new LocationParameterBuilder(true, false);
    string formattedSearchTerm = searchTerm + "%";
    query.AppendLike(LocationColumn.Address1, formattedSearchTerm);
    query.AppendLike(LocationColumn.Address2, formattedSearchTerm);
    query.AppendLike(LocationColumn.Town, formattedSearchTerm);
    query.AppendLike(LocationColumn.PostalTown, formattedSearchTerm);
    query.AppendLike(LocationColumn.County, formattedSearchTerm);

    var locationResult = _locationService.Find(query.GetParameters());
    _locationService.DeepLoad(locationResult, true, Data.DeepLoadType.IncludeChildren, typeof(TList<EnterpriseAndHolding>));
    results.AddRange(ProcessLocationSearches(locationResult));
}

return results;
}

最佳答案

ReactiveAsyncCommand 背后的想法是它有意限制了正在进行的请求的数量。在这种情况下,您想忘记该约束,所以让我们使用常规的 ReactiveCommand 代替:

SearchCommand
    .Select(x => Observable.Start(() => PerformSearch(x), RxApp.TaskPoolScheduler))
    .Switch()
    .ToProperty(this, x => x.SearchResults);

请注意,此处的 Select.Switch 类似于 SelectMany,不同之处在于它将始终保持输入的顺序,同时丢弃未完成的旧输入时间。

Blah blah CancellationTokenSource blah blah TPL

在这种情况下,底层方法本身 (_locationService.DeepLo​​ad) 是同步的 - 不可能以安全的方式取消该方法,所以我们必须让取消的结果运行完成并且忽略结果,这就是我们最终要做的。

编辑:这是一个丑陋的 hack,用于确定项目是否在飞行中:

SearchCommand
    .Do(x => Interlocked.Increment(ref searchesInFlight))
    .Select(x => Observable.Start(() => PerformSearch(x), RxApp.TaskPoolScheduler).Do(x => Interlocked.Decrement(ref searchesInFlight)))
    .Switch()        
    .ToProperty(this, x => x.SearchResults);

关于c# - 在 ReactiveUI 中取消/忽略 ReactiveAsyncCommand 的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17998132/

相关文章:

C# 编译器错误 : "not all code paths return a value"

C#时区计算问题

c# - WPF 中的全局鼠标 Hook

.net - WPF MVVM设置控制焦点

c# - 是否可以强制基于DependencyProperty的绑定(bind)以编程方式重新评估?

c# - 使用 ObservableAsPropertyHelper<> 来自 ReactiveUI 搜索的多个绑定(bind)

.net - Reactive UI 中的各种 WhenAny 方法有什么区别

C#:变量前面的符号

c# - ApplicationServices 解析网络核心中不同范围的实例?

c# - 多个 .WhenAny(...).ToPropertyEx(...) 调用是否应该相互覆盖?