当列表中某个项目的 属性 更改时,ListCollectionView 上的 LiveFiltering 不会重新评估过滤器
LiveFiltering on ListCollectionView doesn't reevaluate the Filter when a property of an item in the list changes
我有一个 class 人,它为 属性 姓名实施 INotifyPropertyChanged:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
Console.WriteLine("PropertyChanged: " + Name + ": " + property);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private string _name;
public string Name
{
get => _name;
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged("Name");
}
}
}
我正在使用带 LiveFiltering 的 ListCollectionView 来显示 ObservableCollection,过滤后仅匹配姓名以 "A":
开头的人
var coll = new ObservableCollection<Person>();
ListCollectionView view = new ListCollectionView(coll)
{
Filter = p => ((Person)p).Name[0]=='A',
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) }
};
将项目添加到集合中后,它们会被正确过滤。
问题出在这里: 当一个人的名字被更改时,过滤器不会被重新评估,这就是我认为 IsLiveFiltering 和 LiveFilteringProperties 最初的目的。
因此,如果我将名称从 "Anna" 更改为 "Elsa",我希望视图会更新并且不再包含该项目。同样,将 "Eric" 更改为 "Arnold" 应该会更新视图,以便更改的项目成为视图中的容器。
var p1 = new Person { Name = "Anna" };
var p2 = new Person { Name = "Eric" };
coll.Add(p1); // view is updated automatically and contains Anna now
coll.Add(p2); // view is updated, but Eric is filtered out
view.Dump(); // shows only "Anna" (LINQPad - Dump)
p1.Name = "Elsa"; // change Anna to Elsa -> the instance p1 should be removed from view (not from collection)
p2.Name = "Arnold"; // change Eric to Arnold -> the instance p2 should now be in the view
//view.Refresh(); // uncommenting this line leads to the behaviour I actually expected from LiveFiltering to be handled automatically.
view.Dump(); // shows "Elsa", but we are filtering for A*
我是否错过了启用某些东西来获得这种行为?我真的不想手动附加到每个 Person 实例的 PropertyChanged - 我仍然希望这就是 LiveFiltering 为我所做的。
编辑:
我在使用更大模型的应用程序中遇到了这个问题,并提取了相关部分以在 LinqPad 中重现该问题。这是完整的 LinqPad 脚本。它还需要使用子句:
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
这是脚本
void Main()
{
var coll = new ObservableCollection<Person>();
ListCollectionView view = new ListCollectionView(coll)
{
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) },
Filter = p => ((Person)p).Name[0] == 'A'
};
var p1 = new Person { Name = "Anna" };
var p2 = new Person { Name = "Eric" };
coll.Add(p1);
coll.Add(p2);
view.Dump();
p1.Name = "Elsa";
p2.Name = "Arnold";
//view.Refresh();
view.Dump();
Debug.Assert(view.Cast<Person>().Single().Name == "Arnold", "Wrong item in view, expected Arnold");
}
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
Console.WriteLine("PropertyChanged: " + Name + ": " + property);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private string _name;
public string Name
{
get => _name;
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged("Name");
}
}
}
您的视图和样本数据在哪里...?
下面的代码肯定能按预期工作。
XAML:
<ListBox x:Name="lb" DisplayMemberPath="Name" />
<Button Content="Filter" Click="Button_Click" />
示例代码:
public partial class MainWindow : Window
{
Person _p = new Person() { Name = "Anna" };
public MainWindow()
{
InitializeComponent();
var coll = new ObservableCollection<Person>() { _p };
ListCollectionView view = new ListCollectionView(coll)
{
Filter = p => ((Person)p).Name[0] == 'A',
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) }
};
lb.ItemsSource = view;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_p.Name = "Elsa";
}
}
在 post 另一个问题之前,您可能应该阅读 this。
我有一个 class 人,它为 属性 姓名实施 INotifyPropertyChanged:
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
Console.WriteLine("PropertyChanged: " + Name + ": " + property);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private string _name;
public string Name
{
get => _name;
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged("Name");
}
}
}
我正在使用带 LiveFiltering 的 ListCollectionView 来显示 ObservableCollection,过滤后仅匹配姓名以 "A":
开头的人var coll = new ObservableCollection<Person>();
ListCollectionView view = new ListCollectionView(coll)
{
Filter = p => ((Person)p).Name[0]=='A',
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) }
};
将项目添加到集合中后,它们会被正确过滤。
问题出在这里: 当一个人的名字被更改时,过滤器不会被重新评估,这就是我认为 IsLiveFiltering 和 LiveFilteringProperties 最初的目的。
因此,如果我将名称从 "Anna" 更改为 "Elsa",我希望视图会更新并且不再包含该项目。同样,将 "Eric" 更改为 "Arnold" 应该会更新视图,以便更改的项目成为视图中的容器。
var p1 = new Person { Name = "Anna" };
var p2 = new Person { Name = "Eric" };
coll.Add(p1); // view is updated automatically and contains Anna now
coll.Add(p2); // view is updated, but Eric is filtered out
view.Dump(); // shows only "Anna" (LINQPad - Dump)
p1.Name = "Elsa"; // change Anna to Elsa -> the instance p1 should be removed from view (not from collection)
p2.Name = "Arnold"; // change Eric to Arnold -> the instance p2 should now be in the view
//view.Refresh(); // uncommenting this line leads to the behaviour I actually expected from LiveFiltering to be handled automatically.
view.Dump(); // shows "Elsa", but we are filtering for A*
我是否错过了启用某些东西来获得这种行为?我真的不想手动附加到每个 Person 实例的 PropertyChanged - 我仍然希望这就是 LiveFiltering 为我所做的。
编辑: 我在使用更大模型的应用程序中遇到了这个问题,并提取了相关部分以在 LinqPad 中重现该问题。这是完整的 LinqPad 脚本。它还需要使用子句:
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
这是脚本
void Main()
{
var coll = new ObservableCollection<Person>();
ListCollectionView view = new ListCollectionView(coll)
{
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) },
Filter = p => ((Person)p).Name[0] == 'A'
};
var p1 = new Person { Name = "Anna" };
var p2 = new Person { Name = "Eric" };
coll.Add(p1);
coll.Add(p2);
view.Dump();
p1.Name = "Elsa";
p2.Name = "Arnold";
//view.Refresh();
view.Dump();
Debug.Assert(view.Cast<Person>().Single().Name == "Arnold", "Wrong item in view, expected Arnold");
}
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
Console.WriteLine("PropertyChanged: " + Name + ": " + property);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private string _name;
public string Name
{
get => _name;
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged("Name");
}
}
}
您的视图和样本数据在哪里...?
下面的代码肯定能按预期工作。
XAML:
<ListBox x:Name="lb" DisplayMemberPath="Name" />
<Button Content="Filter" Click="Button_Click" />
示例代码:
public partial class MainWindow : Window
{
Person _p = new Person() { Name = "Anna" };
public MainWindow()
{
InitializeComponent();
var coll = new ObservableCollection<Person>() { _p };
ListCollectionView view = new ListCollectionView(coll)
{
Filter = p => ((Person)p).Name[0] == 'A',
IsLiveFiltering = true,
LiveFilteringProperties = { nameof(Person.Name) }
};
lb.ItemsSource = view;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_p.Name = "Elsa";
}
}
在 post 另一个问题之前,您可能应该阅读 this。