2009-03-19 15 views
12

Ich habe eine WPF ListView an eine CollectionViewSource gebunden. Die Quelle davon ist an eine Eigenschaft gebunden, die sich ändern kann, wenn der Benutzer eine Option auswählt.CollectionViewSource Filter nicht aktualisiert, wenn die Quelle geändert wird

Wenn die Listenansichtsquelle aufgrund eines geänderten Eigenschaftsereignisses aktualisiert wird, werden alle Informationen korrekt aktualisiert, die Ansicht wird jedoch nicht aktualisiert, um Änderungen im CollectionViewSource-Filter zu berücksichtigen.

Wenn ich einen Handler an das Changed-Ereignis anhänge, an das die Source-Eigenschaft gebunden ist, kann ich die Ansicht aktualisieren, aber dies ist immer noch die alte Ansicht, da die Bindung die Liste noch nicht aktualisiert hat.

Gibt es eine gute Möglichkeit, die Filter zu aktualisieren und neu auszuwerten, wenn sich die Quelle ändert?

Prost

+1

Falls jemand diese findet, es ist ein bisschen veraltet ist jetzt. In WPF 4.5 wurden neue Features hinzugefügt, um das Sortieren, Filtern und Gruppieren von Live-Dateien zu ermöglichen. Siehe http://www.jonathantanoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/ –

Antwort

2

Ändern sich Sie die aktuelle Kollektion Instanz der CollectionViewSource.Source zugewiesen, oder feuern Sie nur PropertyChanged auf der Eigenschaft, dass es gebunden ist?

Wenn die Eigenschaft Source festgelegt ist, sollte der Filter für jedes Element in der neuen Quellensammlung aufgerufen werden, also denke ich, dass etwas anderes passiert. Hast du es probiert, Source manuell zu setzen, anstatt eine Bindung zu verwenden und zu sehen, ob du immer noch dein Verhalten bekommst?

Edit:

Sie verwenden CollectionViewSource.View.Filter das Eigentum oder die CollectionViewSource.Filter Veranstaltung? Die CollectionView wird weggeblasen werden, wenn Sie eine neue Source setzen, also wenn Sie eine Filter auf der CollectionView gesetzt haben, wird es nicht mehr da sein.

+0

Ja, ich ändere die Sammlung und die Elemente in der Listenansicht werden aktualisiert und spiegeln die neue Sammlung wider. Der Filter wird jedoch nicht neu bewertet. Es manuell zu tun, half nicht: ((CollectionViewSource) this.Resources ["logEntryViewSource"]). Quelle = _Application.CurrentLog.Entries.ObservableCollection – Steve

12

Ein später vielleicht wenig, aber diese anderen Benutzer werden so helfen kann ich sowieso posten ...

die CollectionView.Filter auf einem Ereignis Property Basis aktualisiert wird vom Framework nicht unterstützt. Hier gibt es eine Reihe von Lösungen.

1) Implementieren der IEditableObject-Schnittstelle für die Objekte in der Sammlung und Aufrufen von BeginEdit und EndEdit, wenn die Eigenschaft geändert wird, auf der der Filter basiert. Sie können mehr darüber auf dem ausgezeichneten Blog von Dr.WPF hier lesen: Editable Collections by Dr.WPF

2) Erstellen Sie die folgende Klasse und die RefreshFilter-Funktion für das geänderte Objekt.

public class FilteredObservableCollection<T> : ObservableCollection<T> 
{ 
    public void RefreshFilter(T changedobject) 
    { 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedobject, changedobject)); 
    }   
} 

Beispiel:

public class TestClass : INotifyPropertyChanged 
{ 
    private string _TestProp; 
    public string TestProp 
    { 
     get{ return _TestProp; } 
     set 
     { 
      _TestProp = value; 
      RaisePropertyChanged("TestProp"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void RaisePropertyChanged(string propertyName) 
    { 
     var handler = this.PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 


FilteredObservableCollection<TestClass> TestCollection = new FilteredObservableCollection<TestClass>(); 

void TestClass_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    switch (e.PropertyName) 
    { 
     case "TestProp": 
      TestCollection.RefreshFilter(sender as TestClass); 
      break; 
    } 
} 

zum Property Ereignis des Testclass Objekt abonnieren, wenn Sie es schaffen, aber nicht vergessen, die Eventhandler aushängen, wenn das Objekt entfernt wird, sonst führen Speicherlecks

OR

Injizieren Sie die Testcollection in die Testclass und verwenden, um die Funktion innerhalb des RefreshFilter TestProp setter. Wie auch immer, die Magie hier wird von NotifyCollectionChangedAction.Replace bearbeitet, die das Element vollständig aktualisiert.

+0

Ich bin derzeit mit .NET 4.0 stecken und die IEditableObject-Lösung funktioniert wie ein Charme. – Golvellius

+0

Ich konnte das IEditableObject nicht zum Funktionieren bringen. Aber die FilteredObservableCollection funktioniert großartig. Danke für die Lösung –

2

Ich habe eine spezifische Lösung gefunden, um die ObservableCollection-Klasse auf eine zu erweitern, die Änderungen an den Eigenschaften der darin enthaltenen Objekte überwacht here.

Hier ist der Code mit einigen Modifikationen von mir:

namespace Solution 
{ 
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged 
    { 
     protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
     { 
      if (e != null) // There's been an addition or removal of items from the Collection 
      { 
       Unsubscribe(e.OldItems); 
       Subscribe(e.NewItems); 
       base.OnCollectionChanged(e); 
      } 
      else 
      { 
       // Just a property has changed, so reset the Collection. 
       base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 

      } 

     } 

     protected override void ClearItems() 
     { 
      foreach (T element in this) 
       element.PropertyChanged -= ContainedElementChanged; 

      base.ClearItems(); 
     } 

     private void Subscribe(IList iList) 
     { 
      if (iList != null) 
      { 
       foreach (T element in iList) 
        element.PropertyChanged += ContainedElementChanged; 
      } 
     } 

     private void Unsubscribe(IList iList) 
     { 
      if (iList != null) 
      { 
       foreach (T element in iList) 
        element.PropertyChanged -= ContainedElementChanged; 
      } 
     } 

     private void ContainedElementChanged(object sender, PropertyChangedEventArgs e) 
     { 
      OnPropertyChanged(e); 
      // Tell the Collection that the property has changed 
      this.OnCollectionChanged(null); 

     } 
    } 
} 
Verwandte Themen