2009-03-19 16 views
12

Mam ListView WPF związany z CollectionViewSource. Źródło tego jest powiązane z właściwością, która może się zmienić, jeśli użytkownik wybierze opcję.CollectionViewSource Filtr nie odświeżony po zmianie źródła

Gdy źródło widoku listy jest aktualizowane ze względu na zmianę właściwości, wszystko jest uaktualniane poprawnie, ale widok nie jest odświeżany, aby uwzględnić wszelkie zmiany w filtrze CollectionViewSource.

Jeśli dołączę procedurę obsługi do zdarzenia Changed, do którego jest przypisana właściwość Source, można odświeżyć widok, ale jest to nadal stary widok, ponieważ powiązanie nie zaktualizowało jeszcze listy.

Czy istnieje dobry sposób na odświeżenie widoku i ponownej oceny filtrów po zmianie źródła?

Cheers

+1

W przypadku każdy znajdzie to, że jest nieco nieaktualne teraz. W WPF 4.5 dodano nowe funkcje, aby umożliwić sortowanie, filtrowanie i grupowanie "na żywo". Zobacz http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/ –

Odpowiedz

2

Czy zmieniając rzeczywistą instancję kolekcji przypisanego do CollectionViewSource.Source, czy tylko wypalanie PropertyChanged o tej własności, że to wiąże się z?

Jeśli ustawiona jest właściwość Source, filtr powinien zostać wywołany dla każdego elementu z nowej kolekcji źródeł, więc myślę, że dzieje się coś innego. Czy próbowałeś ręcznie ustawić ustawienie, zamiast używać wiązania i sprawdzałeś, czy nadal masz jakieś zachowanie?

Edit:

Używasz CollectionViewSource.View.Filter własności lub zdarzenie CollectionViewSource.Filter? Model CollectionView zostanie zniszczony po ustawieniu nowego Source, więc jeśli masz zestaw Filter na urządzeniu CollectionView, już go tam nie będzie.

+0

Tak, zmieniam kolekcję i przedmioty w widoku listy są aktualizowane, odzwierciedlając nową kolekcję. Filtr nie jest jednak ponownie oceniany. Wykonanie go ręcznie nie pomogło: ((CollectionViewSource) this.Resources ["logEntryViewSource"]). Source = _application.CurrentLog.Entries.ObservableCollection – Steve

12

Trochę późno, być może, ale może to pomóc innym użytkownikom, więc będę pisać tak ...

Aktualizacja CollectionView.Filter oparciu o zdarzenia PropertyChanged nie jest obsługiwany przez ramy. Istnieje wiele rozwiązań w tym zakresie.

1) Implementowanie interfejsu IEditableObject na obiektach wewnątrz kolekcji oraz wywoływanie BeginEdit i EndEdit podczas zmiany właściwości, na której oparty jest filtr. Możesz przeczytać więcej na ten temat na doskonałym blogu Dr.WPF: Editable Collections by Dr.WPF

2) Tworzenie następującej klasy i korzystanie z funkcji RefreshFilter na zmienionym obiekcie.

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

Przykład:

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; 
    } 
} 

Zapisz się do zdarzenia PropertyChanged obiektu TestClass podczas jego tworzenia, ale nie zapomnij, aby odczepić eventhandler gdy obiekt zostanie usunięty, gdyż może to doprowadzić do pamięć przecieki

OR

wstrzyknąć TestCollection karne TestClass oraz korzystać z funkcji RefreshFilter wewnątrz nastawczym TestProp. W każdym razie magia jest tutaj obsługiwana przez funkcję NotifyCollectionChangedAction.Replace, która całkowicie aktualizuje element.

+0

Obecnie utknąłem w .NET 4.0, a rozwiązanie IEditableObject działa jak czar. – Golvellius

+0

Nie można uruchomić obiektu IEditableObject. Ale FilteredObservableCollection działa świetnie. Dzięki za rozwiązanie –

2

Znalazłem konkretne rozwiązanie do rozszerzenia klasy ObservableCollection na taką, która monitoruje zmiany we właściwościach obiektów, które zawiera here.

Oto kod, który z kilkoma modyfikacjami przeze mnie:

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); 

     } 
    } 
}