可观察的集合属性已更改为集合中的项目

我有一个ObservableCollection 。 我已将它绑定到ListBox控件,我已将SortDescriptions到ListBox上的Items集合中,以使列表按我的方式排序。

当在子元素上更改任何属性时,我想在任何时候使用列表。

我的所有子元素都实现了INotifyPropertyChanged

蛮力:

  1. 将处理程序附加到每个子项的每个PropertyChanged事件
  2. 从CollectionViewSource中获取ListCollectionView
  3. 呼叫刷新。

编辑:

1,2的代码将存在于您的代码隐藏中。

对于#1,您可以执行以下操作:

 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** .... } } 

对于#2,在CollectionChanged处理程序中,您可以执行以下操作:

 private void _SomeItem_PropertyChanged(object sender, PropertyChangedEventArgs e) { ListCollectionView lcv = (ListCollectionView)(CollectionViewSource.GetDefaultView(theListBox.ItemsSource)); lcv.Refresh(); } 

EDIT2:但是,在这种情况下,我强烈建议您也检查ListCollectionView.NeedsRefresh并仅在设置时刷新。 如果您的属性已更改且不影响排序,则没有理由重新排序。

这很有效。 每当集合发生变化时,它会重新对集合进行排序。 可能以更有效的方式实现,但这是它的要点。

public partial class TestWindow : Window { ObservableCollection oc; public TestWindow() { InitializeComponent(); // Fill in the OC for testing oc = new ObservableCollection(); 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( ( x ) => ( xC ) ); // Rest converst IEnumerable back to OC and assigns it ObservableCollection temp = new ObservableCollection(); 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 }
public partial class TestWindow : Window { ObservableCollection oc; public TestWindow() { InitializeComponent(); // Fill in the OC for testing oc = new ObservableCollection(); 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( ( x ) => ( xC ) ); // Rest converst IEnumerable back to OC and assigns it ObservableCollection temp = new ObservableCollection(); 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 } 

XAML: