如果更改过滤器,则更新 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 的框架
我通过筛选 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 的框架