2009-06-18 9 views
11

J'ai un ObservableCollection<T>. Je l'ai lié à un contrôle ListBox et j'ai ajouté SortDescriptions à la collection Items sur le ListBox pour faire trier la liste comme je veux.Propriété de collection observable modifiée sur l'élément de la collection

Je souhaite utiliser la liste à TOUS les points lorsqu'une propriété a été modifiée sur un élément enfant.

Tous mes éléments enfants implémentent INotifyPropertyChanged.

+0

Alors, vous lier votre OC à un Listbox et ont le SortDescription sur la zone de liste? – apandit

+0

C'est exact. Quand une propriété d'un élément enfant est modifiée, je voudrais que le tri reflète ce changement. – Nate

Répondre

12

Brute force:

  1. à chaque gestionnaire Joindre événement PropertyChanged pour chaque élément enfant
  2. Prenez le ListCollectionView de votre CollectionViewSource
  3. Refresh appel.

EDIT:

Le code pour 1, 2 habiterait dans votre code-behind.

Pour # 1, vous feriez quelque chose comme:

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

Pour # 2, dans votre gestionnaire CollectionChanged, vous feriez quelque chose comme:

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

EDIT2: Cependant, dans ce cas, je voudrais fortement vous suggérons de vérifier aussi ListCollectionView.NeedsRefresh et seulement rafraîchir si cela est défini. Il n'y a aucune raison de ré-trier si vos propriétés ont changé ce qui n'affecte pas le tri.

+0

Est-ce que ce code vivrait dans mon niveau de présentation? Window.Xaml.Cs? À quoi ressemblerait le code pour les numéros 1 et 2? – Nate

+0

C'est exactement ce dont j'avais besoin. J'ai fini par utiliser seulement la deuxième partie, puisque dans mon cas, j'ai un événement qui cause le changement, alors j'ai seulement besoin de # 2. – Nate

0

Cela fonctionne. Chaque fois que la collection change, elle réorganise la collection. Peut-être faisable d'une manière plus efficace mais c'est l'essentiel de celui-ci.

 

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 n'écoute pas les événements PropertyChanged sur ses éléments, il échouera donc à trier à nouveau lorsqu'une propriété de l'un des éléments est modifiée. http://msdn.microsoft.com/en-us/magazine/dd252944.aspx – Odrade

Questions connexes