2009-06-18 85 views
11

我有一个ObservableCollection<T>。我已经将它绑定到一个ListBox控件,并且我已经添加了SortDescriptions到ListBox上的Items集合,以使列表按我想要的方式排序。可观察收藏物业集合中物品已更改

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

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

+0

所以,你在你的OC绑定到一个列表框和对列表框中sortdescription? – apandit 2009-06-18 21:19:12

+0

这是正确的。当儿童项目的财产发生变化时,我希望能够反映这种变化。 – Nate 2009-06-18 21:22:23

回答

12

蛮力:

  1. 连接处理程序,以每个PropertyChanged事件为每个子项
  2. 抓住的ListCollectionView从CollectionViewSource
  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并只刷新如果设置。没有理由重新排序,如果你的属性已经改变,不影响排序。

+0

这段代码是否在我的表示层中? Window.Xaml.Cs? #1和#2的代码是什么样的? – Nate 2009-06-18 21:25:47

0

This works。只要收集发生变化,它就会重新对收集进行分类。可以以更有效的方式进行操作,但这是它的要点。

 

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>