2009-06-18 6 views
11

Ho un ObservableCollection<T>. L'ho associato a un controllo ListBox e ho aggiunto SortDescriptions alla raccolta Articoli sul ListBox per rendere l'ordinamento della lista come voglio.Proprietà di raccolta osservabili modificate sulla voce nella collezione

Voglio ricorrere all'elenco a ANY punto quando qualsiasi proprietà è stata modificata su un elemento figlio.

Tutti gli elementi figlio implementano INotifyPropertyChanged.

+0

è così, siete vincolante vostro OC ad una casella di riepilogo e avere il sortdescription sulla casella di riepilogo? – apandit

+0

Questo è corretto. Quando viene modificata una proprietà di un elemento figlio, desidero che l'ordinamento rifletta questa modifica. – Nate

risposta

12

forza bruta:

  1. Collegare gestore per ogni evento PropertyChanged per ogni elemento figlio
  2. Afferra il ListCollectionView dal CollectionViewSource
  3. chiamata Aggiorna.

EDIT:

Il codice per 1, 2 vivrebbe nel code-behind.

per # 1, devi fare qualcosa di simile:

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

Per 2 #, nel gestore CollectionChanged, si potrebbe fare qualcosa di simile:

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

EDIT2: Tuttavia, in In questo caso, vorrei fortemente suggerisco di controllare anche ListCollectionView.NeedsRefresh e aggiornare solo se è impostato. Non c'è motivo di riordinare se le tue proprietà sono cambiate e non influenzano l'ordinamento.

+0

Questo codice dovrebbe vivere nel mio livello di presentazione? Window.Xaml.Cs? Che aspetto avrebbero il codice per # 1 e # 2? – Nate

+0

Questo è esattamente ciò di cui avevo bisogno. Ho finito solo usando la seconda parte, dal momento che nel mio caso ho un evento che sta causando il cambiamento, quindi ho solo bisogno di # 2. – Nate

0

Questo funziona. Ogni volta che la collezione cambia, ordina nuovamente la collezione. Potrebbe essere fattibile in un modo più efficiente ma questo è il succo di 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 non ascolta gli eventi PropertyChanged sui suoi elementi, quindi non riuscirà a riordinare quando una proprietà di uno degli elementi viene modificata. http://msdn.microsoft.com/en-us/magazine/dd252944.aspx – Odrade