我通过过滤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
的{{1}}的更改不会触发和更新过滤器。
但是我正在寻找解决方案
更改IObservable
的位置时,我希望SourceList更新filterId
。
结果将是:
filtered
更新后。
应用:在我的wpf应用中,过滤器基于filterId = 2
#2
filterId = 3
#3
,其绑定方式类似于:MyRowClass SelectedRow
。
如果更改<ComboBox ItemsSource="{Binding AvailableRows}" SelectedItem="{Binding SelectedRow}">
,我将无法触发ReadOnlyObservableCollection的刷新。
答案 0 :(得分:1)
多种解决方案:
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的框架