ReactiveUI - DynamicData, переключающийся между потоками на одну коллекцию ReadOnlyObservableCollection - PullRequest
0 голосов
/ 13 апреля 2020

У меня есть ReadOnlyObservableCollection<ItemViewModel>, который я хочу переключать между показом всех элементов и ограничением сверху 2. У меня есть следующий пример кода, который работает.

public class MainViewModel : ReactiveObject
{
    private readonly SourceCache<ItemViewModel, string> _sourceCache = new SourceCache<ItemViewModel, string>(x => x.Text);
    private readonly BehaviorSubject<bool> _toggleSubject = new BehaviorSubject<bool>(false);

    public ReadOnlyObservableCollection<ItemViewModel> ObsCollection;
    public ReactiveCommand<Unit, Unit> ToggleCommand { get; }

    public MainViewModel()
    {
        ToggleCommand = ReactiveCommand.Create(() =>
        {
            _toggleSubject.OnNext(!_toggleSubject.Value);
        });

        _sourceCache.AddOrUpdate(new ItemViewModel() { Text = "a" });
        _sourceCache.AddOrUpdate(new ItemViewModel() { Text = "c" });
        _sourceCache.AddOrUpdate(new ItemViewModel() { Text = "b" });

        IComparer<ItemViewModel> comparer = Comparer<ItemViewModel>.Create((x, y) => x.Text.CompareTo(y.Text));

        var observableChanges = _sourceCache.Connect();

        var limitedStream = _toggleSubject.Where(x => !x).Select(_ => observableChanges.Top(comparer: comparer, size: 2));
        var fullStream = _toggleSubject.Where(x => x).Select(_ => observableChanges.Sort(comparer));

        Observable.Merge(limitedStream, fullStream)
            .Switch()
            .Bind(out ObsCollection)
            .Subscribe();
    }
}

Используя ToggleCommand, ObsCollection испускает ожидаемый результат. Но когда я пытаюсь наблюдать изменения (ViewModel.ObsCollection.ToObservableChangeSet()) в ReactiveRecyclerViewAdapter<ItemViewModel>, при переключении отображаются неправильные результаты. Вместо отображения a, b, c в списке отображаются a, b, b. Отладка с помощью реализации ReactiveRecyclerViewAdapter Я вижу, что change.Range.Index установлен на -1 вместо того, что я ожидал 0. Я думаю, именно поэтому последнее значение не обновляется.

        case ListChangeReason.AddRange:
            NotifyItemRangeInserted(change.Range.Index, change.Range.Count);
            break;
        case ListChangeReason.RemoveRange:
        case ListChangeReason.Clear:
            NotifyItemRangeRemoved(change.Range.Index, change.Range.Count);
            break;

Почему любое изменение начинается с индекса -1? Этот тип реализации действителен. У меня есть полный проект, чтобы воспроизвести это.

1 Ответ

1 голос
/ 14 апреля 2020

Объединение наборов изменений в динамических данных c с использованием оператора слияния rx не будет работать. Это связано с тем, что последующие операторы не могут понять, что изменения происходят из разных источников, что приводит к непредсказуемым результатам.

Вместо данных Dynami c имеются собственные операторы, которые позволяют различным средствам объединять наборы изменений. Примерами этого являются операторы And и Or, которые применяют логическое объединение ко всей коллекции. Однако в этом случае мы меняем результат, поэтому правильный способ - использовать перегрузку данных Dynami c, равную Switch, которая выгружает предыдущие результаты и загружает новые результаты при срабатывании переключателя.

var toggled = _toggleSubject
     //when the toggle subject changes select top values or all accordingly 
    .Select(b => b ? observableChanges.Top(comparer: comparer, size: 2) : observableChanges.Sort(comparer))
    //this is a dynamic data overload of switch which flattens the nested observable
    .Switch(); 

...