我通过过滤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
更新后。
Appliation:在我的wpf应用程序中,过滤器基于MyRowClass SelectedRow
,其绑定方式如下:<ComboBox ItemsSource="{Binding AvailableRows}" SelectedItem="{Binding SelectedRow}">
。如果更改SelectedRow
,我将无法触发刷新ReadOnlyObservableCollection的方法。
多种解决方案:
[1)使用ReactiveUI
ReactiveUI是一个考虑了响应式编程和动态数据的自以为是的MVVM框架。因为您已经提到用例是WPF应用程序,所以建议在顶部使用ReactiveUI。由于您为过滤器使用了Viewmodel属性,因此该视图模型应实现INotifyPropertyChanged,它与reactui一起使您可以编写:
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;
}
这将在谓词中转换您的值,非常类似于您的原始示例,只不过为可观察对象产生的每个值都重建了过滤器。
然后进入您的源列表管道
SL.Connect()
.Filter(observableFilter)
.Bind(out ReadOnlyObservableCollection<DemoClass> temp)
.Subscribe();
这次,您的过滤器每次更改都会重新应用
** 2)使用主题**
非常类似于先前的解决方案,但是如果您不想使用,则不使用reactui。此方法将使用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);
最后一点是唯一的区别。
我建议您使用第一个解决方案,并学习reactui框架,因为它是负责维护DynamicData的框架