2009-03-19 8 views
12

J'ai un ListView WPF lié à une CollectionViewSource. La source de cela est liée à une propriété, qui peut changer si l'utilisateur sélectionne une option. Lorsque la source de la vue liste est mise à jour en raison d'un événement de modification de propriété, tout est mis à jour correctement, mais la vue n'est pas actualisée pour prendre en compte les modifications apportées au filtre CollectionViewSource.Le filtre CollectionViewSource n'est pas actualisé lorsque la source est modifiée

Si j'attache un gestionnaire à l'événement Changed auquel la propriété Source est liée, je peux actualiser la vue, mais il s'agit toujours de l'ancienne vue, car la liaison n'a pas encore mis à jour la liste.

Existe-t-il un moyen décent pour actualiser la vue et réévaluer les filtres lorsque la source change?

Vive

+1

Dans le cas où quelqu'un trouve cela, il est un peu obsolète maintenant. Dans WPF 4.5, de nouvelles fonctionnalités ont été ajoutées pour permettre le tri, le filtrage et le regroupement "en direct". Vous voyez http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/ –

Répondre

2

Vous changer l'instance de collection réelle affectée à la CollectionViewSource.Source, ou êtes-vous simplement PropertyChanged sur tirent la propriété qu'il est lié?

Si la propriété Source est définie, le filtre doit être rappelé pour chaque élément de la nouvelle collection source, donc je pense que quelque chose d'autre se produit. Avez-vous essayé de définir manuellement Source au lieu d'utiliser une liaison et de voir si vous avez toujours votre comportement?

Edit:

Utilisez-vous CollectionViewSource.View.Filter la propriété ou l'événement CollectionViewSource.Filter? Le CollectionView sera époustouflé lorsque vous définissez un nouveau Source, donc si vous aviez un Filter réglé sur le CollectionView il ne sera plus là.

+0

Oui, je change la collection, et les éléments dans la vue de liste sont mis à jour reflétant la nouvelle collection. Cependant, le filtre n'est pas réévalué. Le faire manuellement n'a pas aidé: ((CollectionViewSource) this.Resources [ "logEntryViewSource"]) Source = _application.CurrentLog.Entries.ObservableCollection – Steve

12

Un peu tard peut-être, mais cela peut aider d'autres utilisateurs si je posterai quand même ...

Mise à jour du CollectionView.Filter basé sur un événement PropertyChanged est pas pris en charge par le cadre. Il y a un certain nombre de solutions autour de cela.

1) Implémenter l'interface IEditableObject sur les objets de votre collection et appeler BeginEdit et EndEdit lors de la modification de la propriété sur laquelle le filtre est basé. Vous pouvez en lire plus à ce sujet sur l'excellent blog du Dr.WPF ici: Editable Collections by Dr.WPF

2) Création de la classe suivante et utilisation de la fonction RefreshFilter sur l'objet modifié.

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

Exemple:

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

Abonnez-vous à l'événement PropertyChanged de l'objet TestClass lorsque vous créez, mais ne pas oublier de décrocher le eventhandler lorsque l'objet se retire, sinon cela peut conduire à fuites de mémoire

OU

Injecter le TestCollection dans le TestClass et utiliser la fonction de RefreshFilter à l'intérieur du poseur TestProp. De toute façon, la magie ici est travaillée par le NotifyCollectionChangedAction.Replace qui met à jour l'élément entièrement.

+0

Je suis actuellement coincé avec .NET 4.0 et la solution IEditableObject fonctionne comme un charme.. – Golvellius

+0

Je n'ai pas réussi à faire fonctionner IEditableObject. Mais le FilteredObservableCollection fonctionne très bien. Merci pour la solution –

2

J'ai trouvé une solution spécifique pour étendre la classe ObservableCollection à une classe qui surveille les changements dans les propriétés des objets qu'elle contient here.

est ici que le code avec quelques modifications par moi:

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

     } 
    } 
} 
Questions connexes