C# 集合中项的可观察集合属性已更改
我有一个C# 集合中项的可观察集合属性已更改,c#,wpf,sorting,collections,observablecollection,C#,Wpf,Sorting,Collections,Observablecollection,我有一个可观察的收集。我已将其绑定到ListBox控件,并已将SortDescriptions添加到ListBox上的Items集合中,以使列表按我所需的方式排序 当子元素上的任何属性发生更改时,我希望在任何点使用列表 所有我的子元素都实现了INotifyPropertyChanged暴力: 将处理程序附加到每个子项的每个PropertyChanged事件 从CollectionViewSource获取ListCollectionView 呼叫刷新 编辑: 1,2的代码将存在于您的代码背后 对于
可观察的收集
。我已将其绑定到ListBox控件,并已将SortDescriptions
添加到ListBox上的Items集合中,以使列表按我所需的方式排序
当子元素上的任何属性发生更改时,我希望在任何点使用列表
所有我的子元素都实现了INotifyPropertyChanged
暴力:
private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach( SomeItem item in e.NewItems)
{
item.PropertyChanged += new PropertyChangedEventHandler(_SomeItem_PropertyChanged);
}
break;
....
**HANDLE OTHER CASES HERE**
....
}
}
private void _SomeItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
ListCollectionView lcv = (ListCollectionView)(CollectionViewSource.GetDefaultView(theListBox.ItemsSource));
lcv.Refresh();
}
对于#2,在CollectionChanged处理程序中,您可以执行以下操作:
private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach( SomeItem item in e.NewItems)
{
item.PropertyChanged += new PropertyChangedEventHandler(_SomeItem_PropertyChanged);
}
break;
....
**HANDLE OTHER CASES HERE**
....
}
}
private void _SomeItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
ListCollectionView lcv = (ListCollectionView)(CollectionViewSource.GetDefaultView(theListBox.ItemsSource));
lcv.Refresh();
}
编辑2:
但是,在这种情况下,我强烈建议您也选中ListCollectionView.NeedsRefresh,并且仅在设置了该选项时才刷新。如果您的属性已更改,但不影响排序,则没有理由重新排序。此操作有效。每当集合发生更改时,它都会对集合重新排序。可能以更有效的方式可行,但这是它的要点
public partial class TestWindow : Window {
ObservableCollection<TestClass> oc;
public TestWindow() {
InitializeComponent();
// Fill in the OC for testing
oc = new ObservableCollection<TestClass>();
foreach( char c in "abcdefghieeddjko" ) {
oc.Add( new TestClass( c.ToString(), c.ToString(), c.GetHashCode() ) );
}
lstbox.ItemsSource = oc;
// Set up the sorting (this is how you did it.. doesn't work)
lstbox.Items.SortDescriptions.Add( new SortDescription("A", ListSortDirection.Ascending) );
// This is how we're going to do it
oc.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler( oc_Sort );
}
void oc_Sort( object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e ) {
// This sorts the oc and returns IEnumerable
var items = oc.OrderBy<TestClass, int>( ( x ) => ( x.C ) );
// Rest converst IEnumerable back to OC and assigns it
ObservableCollection<TestClass> temp = new ObservableCollection<TestClass>();
foreach( var item in items ) {
temp.Add( item );
}
oc = temp;
}
private void Button_Click( object sender, RoutedEventArgs e ) {
string a = "grrrr";
string b = "ddddd";
int c = 383857;
oc.Add( new TestClass( a, b, c ) );
}
}
public class TestClass : INotifyPropertyChanged {
private string a;
private string b;
private int c;
public TestClass( string f, string g, int i ) {
a = f;
b = g;
c = i;
}
public string A {
get { return a; }
set { a = value; OnPropertyChanged( "A" ); }
}
public string B {
get { return b; }
set { b = value; OnPropertyChanged( "B" ); }
}
public int C {
get { return c; }
set { c = value; OnPropertyChanged( "C" ); }
}
#region onpropertychanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( string propertyName ) {
if( this.PropertyChanged != null ) {
PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
}
}
#endregion
}
公共部分类TestWindow:Window{
可观察收集oc;
公共测试窗口(){
初始化组件();
//填写OC进行测试
oc=新的ObservableCollection();
foreach(在“abcdefghiedjko”中的字符c){
Add(新的TestClass(c.ToString(),c.ToString(),c.GetHashCode());
}
lstbox.ItemsSource=oc;
//设置排序(这是您如何完成的..不起作用)
lstbox.Items.SortDescriptions.Add(新的SortDescription(“A”,ListSortDirection.升序));
//这就是我们要做的
oc.CollectionChanged+=新系统.Collections.Specialized.NotifyCollectionChangedEventHandler(oc\U排序);
}
无效oc_排序(对象发送方,System.Collections.Specialized.NotifyCollectionChangedEventArgs e){
//这将对oc进行排序并返回IEnumerable
var项目=oc.OrderBy((x)=>(x.C));
//Rest converst IEnumerable返回给OC并赋值
ObservableCollection temp=新的ObservableCollection();
foreach(项目中的var项目){
临时添加(项目);
}
oc=温度;
}
私有无效按钮\u单击(对象发送者,路由目标e){
字符串a=“grrrr”;
字符串b=“ddd”;
int c=383857;
oc.Add(新的测试类(a、b、c));
}
}
公共类TestClass:INotifyPropertyChanged{
私人字符串a;
私有字符串b;
私人INTC;
公共测试类(字符串f、字符串g、int i){
a=f;
b=g;
c=i;
}
公共字符串A{
获取{返回一个;}
设置{a=value;OnPropertyChanged(“a”);}
}
公共字符串B{
获取{return b;}
设置{b=value;OnPropertyChanged(“b”);}
}
公共INTC{
获取{return c;}
设置{c=value;OnPropertyChanged(“c”);}
}
#已更改属性上的区域
公共事件属性更改事件处理程序属性更改;
受保护的无效OnPropertyChanged(字符串propertyName){
if(this.PropertyChanged!=null){
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
#端区
}
XAML:
那么,您将OC绑定到一个列表框,并在列表框上有sortdescription?这是正确的。当子项的属性发生更改时,我希望排序反映此更改。此代码是否存在于我的表示层中?Window.Xaml.Cs?#1和#2的代码是什么样子的?这正是我需要的。我最后只使用了第二部分,因为在我的例子中,我有一个导致更改的事件,所以我只需要#2。ObservableCollection不侦听其元素上的PropertyChanged事件,因此当其中一个元素的属性更改时,它将无法重新排序。