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


我有一个 ObservableCollection<T>。我已将它绑定到ListBox控件,我已添加 SortDescriptions 到ListBox上的Items集合,使列表排序我想要的方式。

我想在名单上求助 任何 在子元素上更改任何属性时指向。

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


3558
2018-06-18 20:51


起源

那么,您是将OC绑定到列表框并在列表框中进行排序? - apandit
那是对的。当子项的属性更改时,我希望排序反映此更改。 - Nate


答案:


蛮力:

  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并仅在设置时刷新。如果您的属性已更改且不影响排序,则没有理由重新排序。


12
2018-06-18 21:24



这段代码会存在于我的演示层吗? Window.Xaml.Cs?代码#1和#2的代码是什么样的? - Nate
这正是我所需要的。我最终只使用了第二部分,因为在我的情况下,我有一个导致更改的事件,所以我只需要#2。 - Nate


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


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
    }

XAML:

<Window x:Class =“ServiceManager.TestWindow”
    的xmlns = “http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    的xmlns:X = “http://schemas.microsoft.com/winfx/2006/xaml”
    Title =“TestWindow”Height =“500”Width =“500”>
    <DockPanel中>
        <ListBox ItemsSource =“{Binding}”x:Name =“lstbox”>
            <ListBox.ItemTemplate>
                <Da​​taTemplate中>
                    <StackPanel Orientation =“Horizo​​ntal”>
                        <Label Content =“{Binding Path = A}”/>
                        <Label Content =“{Binding Path = B}”/>
                        <Label Content =“{Binding Path = C}”/>
                    </ StackPanel中>
                </ DataTemplate中>
            </ListBox.ItemTemplate>
        </列表框>
        <Button Click =“Button_Click”Content =“Click”/>
    </ DockPanel中>
</窗口>

0
2018-06-18 21:36



ObservableCollection <T>不会在其元素上侦听PropertyChanged事件,因此当其中一个元素的属性发生更改时,将无法重新排序。 msdn.microsoft.com/en-us/magazine/dd252944.aspx - Odrade