我有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;
}
答案 0 :(得分:1)
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.DeepLoad
)是同步的 - 不可能以安全的方式取消该方法,因此我们必须让取消的结果运行完成并忽略结果,是我们最终会在这里做的。
编辑:这是一个丑陋的黑客,可以判断物品是否在飞行中:
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);