代码之家  ›  专栏  ›  技术社区  ›  Nate CSS Guy

集合中项的Observable Collection属性已更改

  •  11
  • Nate CSS Guy  · 技术社区  · 16 年前

    我有一个 ObservableCollection<T> . 我已将它绑定到列表框控件,并添加了 SortDescriptions 到列表框上的项集合,以使列表按我的需要排序。

    我想把名单寄到 任何 子元素上任何属性更改时的点。

    所有子元素实现 INotifyPropertyChanged .

    2 回复  |  直到 12 年前
        1
  •  12
  •   micahtan    16 年前

    蛮力:

    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();
    }
    

    编辑2: 但是,在这种情况下,我会 强烈地 建议您也检查listcollectionview.needsrefresh,如果设置了,则只刷新。如果您的属性发生了不影响排序的更改,则没有理由重新排序。

        2
  •  0
  •   apandit    16 年前

    这是可行的。每当集合更改时,它会对集合重新排序。也许可以以更有效的方式实现,但这就是其中的要点。

    
    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>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="{Binding Path=A}"/>
                            <Label Content="{Binding Path=B}"/>
                            <Label Content="{Binding Path=C}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button Click="Button_Click" Content="Click" />
        </DockPanel>
    </Window>