2009-03-19 17 views
12

Tengo un WPF ListView vinculado a un CollectionViewSource. La fuente de eso está ligada a una propiedad, que puede cambiar si el usuario selecciona una opción.CollectionViewSource Filtro no actualizado cuando se cambia Source

Cuando el origen de la vista de lista se actualiza debido a un evento de cambio de propiedad, todo se actualiza correctamente, pero la vista no se actualiza para tener en cuenta los cambios en el filtro CollectionViewSource.

Si adjunto un controlador al evento Changed al que está vinculada la propiedad Source, puedo actualizar la vista, pero esta sigue siendo la vista anterior, ya que el enlace no ha actualizado la lista todavía.

¿Hay alguna manera decente de actualizar y volver a evaluar los filtros cuando cambia la fuente?

Saludos

+1

En caso de que alguien encuentra esto, que es un poco fuera de fecha ahora. En WPF 4.5, se agregaron nuevas características para permitir la clasificación, el filtrado y la agrupación "en vivo". Ver http://www.jonathanantoine.com/2011/10/05/wpf-4-5-%E2%80%93-part-10-live-shaping/ –

Respuesta

2

¿Está cambiando la instancia colección real asignado a la CollectionViewSource.Source, o simplemente que disparaban PropertyChanged en la propiedad que está destinado a?

Si se establece la propiedad Source, el filtro se debe recuperar para cada elemento en la nueva colección de origen, así que estoy pensando que algo más está sucediendo. ¿Has intentado configurar Source manualmente en lugar de usar un enlace y ver si todavía obtienes tu comportamiento?

Editar:

¿Está utilizando CollectionViewSource.View.Filter propiedad, o el evento CollectionViewSource.Filter? El CollectionView saldrá volando cuando configure un nuevo Source, por lo que si tuviera un Filter configurado en el CollectionView, ya no estará allí.

+0

Sí, estoy cambiando la colección y los artículos en la vista de lista se actualizan reflejando la nueva colección. Sin embargo, el filtro no se vuelve a evaluar. Hacerlo manualmente no ayudó: ((CollectionViewSource) this.Resources ["logEntryViewSource"]). Source = _application.CurrentLog.Entries.ObservableCollection – Steve

12

Un poco tarde tal vez, pero esto puede ayudar a otros usuarios de manera voy a publicar de todos modos ...

Actualización del CollectionView.Filter basado en un evento PropertyChanged no está soportada por el marco. Existen varias soluciones al respecto.

1) Implementando la interfaz IEditableObject en los objetos dentro de su colección, y llamando a BeginEdit y EndEdit al cambiar la propiedad en la que se basa el filtro. Puedes leer más sobre esto en el excelente blog de Dr.WPF aquí: Editable Collections by Dr.WPF

2) Creando la siguiente clase y usando la función RefreshFilter en el objeto cambiado.

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

Ejemplo:

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

Suscribirse al evento PropertyChanged del objeto TestClass cuando lo cree, pero no se olvide de desenganchar el manejador de sucesos cuando el objeto se retira, de lo contrario esto puede dar lugar a pérdidas de memoria

O

Inyectar el TestCollection en el TestClass y utilizar la función RefreshFilter dentro del setter TestProp. De todos modos, la magia aquí es trabajada por NotifyCollectionChangedAction.Replace que actualiza el elemento por completo.

+0

Actualmente estoy atascado con .NET 4.0 y la solución IEditableObject funciona como un amuleto. – Golvellius

+0

No pude conseguir que IEditableObject funcione. Pero FilteredObservableCollection funciona muy bien. Gracias por la solución –

2

Encontré una solución específica para extender la clase ObservableCollection a una que supervisa los cambios en las propiedades de los objetos que contiene here.

Así es que el código con algunas modificaciones por mí:

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

     } 
    } 
} 
Cuestiones relacionadas