如果更改过滤器,则更新 ReadOnlyObservableCollection

Update ReadOnlyObservableCollection if Filter is changed

我通过筛选 SourceList 派生了一个 ReadOnlyObservable 集合。 过滤器取决于一些不可观察的变量。 当过滤器中的值发生变化时,如何确保集合得到更新?

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}">。 如果 SelectedRow 更改,我无法找到如何触发 ReadOnlyObservableCollection 的刷新。

多个解决方案:

1) 使用 ReactiveUI

ReactiveUI 是一个固执己见的 MVVM 框架,它考虑到了响应式编程和动态数据。 因为您已经提到您的用例是 WPF 应用程序,所以建议在顶部使用 ReactiveUI。由于您正在为您的过滤器使用 Viewmodel 属性,因此该 Viewmodel 应该实现 INotifyPropertyChanged,它与 reactiveui 允许您编写:

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

这会从 属性 FilterId 中创建一个 IObservable<int>,这样当您的视图更改值时,WPF 绑定将更新视图模型 属性,并且observableFilter 产生一个新值。 添加方法

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

这会在谓词中转换您的值,就像在您的原始示例中一样,除了为可观察对象产生的每个值重建过滤器。

然后在您的源列表管道中

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

这一次,您的过滤器每次更改都会重新应用

** 2) 使用主题 **

与之前的解决方案非常相似,但如果您不想的话,请不要使用 reactiveui。 此方法将使用 Subject<T> 作为过滤器的可观察源。

在你的视图模型中 class 你会写一个 属性 这样的

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);

最后一点是唯一的区别。

我建议您使用第一种解决方案并学习 reactui 框架,因为它是负责维护 DynamicData 的框架