Обновите ReadOnlyObservableCollection, если фильтр изменен - PullRequest
0 голосов
/ 29 октября 2019

Я получаю коллекцию ReadOnlyObservable, отфильтровывая SourceList. Фильтр зависит от некоторых ненаблюдаемых переменных. Как обеспечить обновление коллекции при изменении значений в фильтре?

using System;
using System.Collections.ObjectModel;
using DynamicData;

namespace ReadOnlyTest
{
    class DemoClass
    {
        public int Id;
        public String Name;
    }

    class Program
    {
          static void Main(string[] args)
        {
            SourceList<DemoClass> SL = new SourceList<DemoClass>();
            ReadOnlyObservableCollection<DemoClass> filtered;

            int filterId = 2;        

            SL.Add(new DemoClass() { Id = 1, Name = "#1" });
            SL.Add(new DemoClass() { Id = 2, Name = "#2" });
            SL.Add(new DemoClass() { Id = 3, Name = "#3" });

            SL.Connect()
                .Filter(entr => { return entr.Id == filterId; })
                .Bind(out ReadOnlyObservableCollection<DemoClass> temp)
                .Subscribe();
            filtered = temp;

            System.Console.WriteLine("filterId = 2");

            foreach (DemoClass dc in filtered)
            {
                System.Console.WriteLine(dc.Name);
            }

            filterId = 3;
            System.Console.WriteLine("filterId = 3");
            foreach (DemoClass dc in filtered)
            {
                System.Console.WriteLine(dc.Name);
            }

            System.Console.ReadLine();
        }
    }
}

Вывод:

filterId = 2
#2
filterId = 3
#2

Я понимаю, откуда это происходит. Очевидно, что изменение filterId, которое не является IObservable, не вызывает и не обновляет фильтр.

Однако я ищу решение, в котором при изменении filterId я хочу, чтобы SourceList обновил filtered.

Таким образом, результат будет:

filterId = 2
#2
filterId = 3
#3

после обновления.

Применение: В моем приложении wpf фильтр основан на MyRowClass SelectedRow, который связан как: <ComboBox ItemsSource="{Binding AvailableRows}" SelectedItem="{Binding SelectedRow}">. Я не смог выяснить, как можно вызвать обновление ReadOnlyObservableCollection, если SelectedRow изменено.

1 Ответ

1 голос
/ 30 октября 2019

Несколько решений:

1) Использование ReactiveUI

ReactiveUI - это продуманный MVVM-каркас, созданный с учетом программирования и динамических данных Reactive. Поскольку вы упомянули, что ваш вариант использования является приложением WPF, рекомендуется использовать ReactiveUI сверху. Поскольку вы используете свойство Viewmodel для своего фильтра, эта модель представления должна реализовывать INotifyPropertyChanged, который с помощью реактивной функции позволяет вам написать:

var observableFilter = this.WhenAnyValue(viewModel => viewModel.FilterId)
.Select(MakeFilter);

Это делает IObservable<int> из свойства FilterId, так чтокогда ваше представление меняет значение, привязка WPF обновит свойство viewmodel, а observableFilter создаст новое значение. Добавьте метод

private Func<DemoClass,bool> MakeFilter(int id)
{
    return demoClass => demoClass.Id == id;
}

, который преобразует ваше значение в предикат, так же, как в исходном примере, за исключением того, что фильтр перестраивается для каждого значения, создаваемого наблюдаемой.

затем в вашем исходном спискеpipe

    SL.Connect()
      .Filter(observableFilter)
      .Bind(out ReadOnlyObservableCollection<DemoClass> temp)
      .Subscribe();

На этот раз ваш фильтр применяется каждый раз, когда он меняется

** 2) Использование объекта **

Очень похоже на предыдущее решение, ноне использует реактивные, если вы не хотите. Этот метод будет использовать Subject<T> в качестве источника, наблюдаемого для вашего фильтра.

В вашем классе viewmodel вы бы написали свойство, подобное этому

private Subject<int> idChanged = new Subject<int>();
private int _filterId;
public FilterId 
{ 
    get => _filterId; 
    set 
    {
        _filterId = value; 
        idChanged.OnNext(value);
    } 
}

Этот Subject<int> является объектом, которыйявляется IObservable, и его метод OnNext(int value) заставит его произвести значение. Затем этот предмет используется почти так же, как и первое решение:

var observableFilter = idChanged
.Select(MakeFilter);

Этот последний бит является единственным отличием.

Я рекомендую вам использовать первое решение и изучитьинтегрированная платформа, которая отвечает за поддержку DynamicData

...