2009-06-18 1 views
11

У меня есть ObservableCollection<T>. Я привязал его к элементу управления ListBox, и я добавил SortDescriptions в коллекцию Items в ListBox, чтобы сделать список отсортированным, как я хочу.Наблюдаемая коллекция Собственность изменена по предмету в коллекции

Я хочу прислать список на ANY указать, если какое-либо свойство изменено на дочерний элемент.

Все мои дочерние элементы реализуют INotifyPropertyChanged.

+0

Итак, вы связываете свой OC к Listbox и имеют sortdescription на ListBox? – apandit

+0

Это правильно. Когда свойство дочернего элемента изменяется, я хотел бы, чтобы сортировка отражала это изменение. – Nate

ответ

12

Грубая сила:

  1. Присоединить обработчик к каждому событию PropertyChanged для каждого дочернего элемента
  2. захватить ListCollectionView от вашего CollectionViewSource
  3. Вызов Refresh.

EDIT:

Код для 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

+0

Это именно то, что мне нужно. В итоге я использовал только вторую часть, так как в моем случае у меня есть событие, которое вызывает изменение, поэтому мне нужно только 2. – Nate

0

Это работает. Всякий раз, когда коллекция изменяется, она повторно сортирует коллекцию. Могу быть выполнимым более эффективным способом, но это и есть суть этого.

 

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> 
+2

ObservableCollection не прослушивает события PropertyChanged в своих элементах, поэтому при повторном сортировке свойства одного из элементов не будет повторно сортироваться. http://msdn.microsoft.com/en-us/magazine/dd252944.aspx – Odrade