问题
ReactiveUI recommends the use of dynamic-data going forward. I try to migrate what make sense as I have to work in my view models .
Recently I've been facing a problem that I just can't seem able to find a solution to. In one of my pages, dynamic data is used with a SourceCache
of 100,000 items on which I need to apply dynamic filters and sorts.
This issue is that even if filtering on 100,000 happens relatively fast on a mobile device the user has no idea if we are done filtering or not. The easiest way to let the user know we're doing something is using IsRefreshing
on my ListView
.
This is where the problem starts...
I'm able to know when filtering starts since I'm the one building the Observable trigger, I just can't find a reliable way to know when the filtering completes (not always).
The first time a filter runs and returns 0 results things work as expected, it just won't trigger 0 results (changes) again after the initial time until we get at least one change in the results.
This means that I can show and hide a refresh spinner as long as the filter yields "changes" to the result set but as soon as the user hits 0 results, subsequent 0 result searches will yield 0 changes to the results and won't trigger the Observable... The spinner will just keep on spinning until a filter yields at least 1 change.
Here's code to that illustrates the issue: (using a SourceList
for simplicity)
var disposables = new CompositeDisposable();
var sourceList = new SourceList<string>();
ReadOnlyObservableCollection<string> results;
using (disposables)
{
// Create 100,000 dummy strings to start with
sourceList.Edit(
(innerList) =>
{
Enumerable
.Range(1, 100000)
.ForEach(x => innerList.Add(x.ToString()));
});
// Fake text trigger to replicate WhenAnyValue
var trigger = new Subject<string>();
disposables.Add(trigger);
// Dynamic filter
var filter = trigger
.Do(s =>
{
Console.WriteLine($"\r\nSearching for: {s}");
})
.Select(
searchTerm =>
{
Func<string, bool> searcher = item => item.StartsWith(
searchTerm,
StringComparison.InvariantCultureIgnoreCase);
return searcher;
});
disposables.Add(
sourceList
.Connect()
.Filter(filter)
.Bind(out results)
.Subscribe(
x =>
{
Console.WriteLine($"Got {results.Count} results");
}));
// Those works as expected
trigger.OnNext("99999");
trigger.OnNext("9999");
trigger.OnNext("9998");
trigger.OnNext("1");
trigger.OnNext("100001");
// At this point, because there aren't any changes we don't get any more results
// until we return something other than 0 items.
trigger.OnNext("100002");
trigger.OnNext("100003");
// This will get results as expected.
trigger.OnNext("99998");
}
This code give the following results.. notice how I don't get any results for 100002 and 100003:
Searching for: 99999
Got 1 results
Searching for: 9999
Got 11 results
Searching for: 9998
Got 11 results
Searching for: 1
Got 11112 results
Searching for: 100001
Got 0 results
Searching for: 100002
Searching for: 100003
Searching for: 99998
Got 1 results
I would have expected the Observable to trigger even if it is with 0 changes since I just ran a filter and am most likely interested in the outcome.
Anyone has any idea how to get around this? Am I doing something wrong?
回答1:
The problem you have observed is caused by the historic design decision to suppress empty notifications which I made during the early days of Dynamic Data. This was for performance reasons. I was developing an extremely busy trading system which was dynamically filtering several times a second on a large data set. The result was exposed as a derived cache which was subsequently consumed by dozens of other functions. Suppressing empty results worked wonders for the performance of that system. However the decision was poor as it has had the side effect which has hit you hard.
A much better solution would be for that restriction be removed and allow consumers to use the .NotEmpty()
operator to opt in. Doing so would remove your issue.
Could you please submit an issue on Github and I will remove the restriction.
来源:https://stackoverflow.com/questions/54677930/tracking-the-execution-of-dynamic-data-filters-and-sorts