2010-01-29 10 views
13

He escrito un Control WPF personalizado con extensión de búsqueda, llamémoslo MyControl. El control es descendiente de una clase ItemsControl.WPF CollectionViewSource ¿Vistas múltiples?

Así que alimentar a la fuente de los datos para de esta manera:

el propio control utiliza

protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue) 
{ 
    if (newValue != null) 
    { 
     ICollectionView view = CollectionViewSource.GetDefaultView(newValue); 
     view.Filter += this.FilterPredicate; 
    } 

    if (oldValue != null) 
    { 
     ICollectionView view = CollectionViewSource.GetDefaultView(oldValue); 
     view.Filter -= this.FilterPredicate; 
    } 

    base.OnItemsSourceChanged(oldValue, newValue); 
} 

para filtrar la vista de la colección de origen (que muestra por lo tanto, en un ListBox interior).

Supongamos ahora que tenemos 10 de estos MyControls definidos en XAML con el mismo DynamicSource. El problema es que si uno de ellos aplica el filtro en la colección fuente, también afectará a todas las demás instancias.

¿Cómo cambiaría el control para evitar este comportamiento?

Respuesta

26

En situaciones como esta, generalmente desea crear una instancia de ICollectionView por separado para cada uso de la colección filtrado de forma diferente. No es una buena idea usar una implementación específica de ICollectionView ya que es posible que el tipo CollectionView necesite cambiar si ItemsSource está vinculado a un tipo diferente de colección. Usando

ICollectionView filteredView = new CollectionViewSource { Source=newValue }.View; 

le dará un ICollectionView que es el tipo correcto de forma automática.

Desafortunadamente, lo que puede encontrar en este caso es que es muy difícil aplicar una colección diferente al ItemsPresenter de su control personalizado ya que toda la magia la hace la clase base ItemsControl y depende de ItemsSource/Propiedades de elementos que administra. Esto ocurre cuando se usa algo similar a la plantilla predeterminada de ItemsControl.

Si de hecho está usando un control ListBox por separado (y TemplateBinding todas las propiedades de ItemsSource si lo necesita) dentro de su ControlTemplate entonces debería simplemente agregar un nuevo ICollectionView DP (recomendaría solo lectura) en su control para mantener su versión filtrada de la colección y enlazar la plantilla ListSource de ListBox a esa nueva propiedad.

+0

Muy bien, realmente funciona ... ¡Muchas gracias! Solo una pregunta noobie - es .RegisterReadOnly() ¿a qué te refieres con decir 'readonly'? –

+0

Lo estoy preguntando porque en ItemsSourceChanged estoy configurando ItemsSourceView = new CollectionViewSource {Source = newValue} .View, donde ItemsSourceView es un DP, por lo que no puedo simplemente eliminar el setter. –

+2

Sí. Es un poco más que simplemente cambiar la inicialización: privado estático de solo lectura DependencyPropertyKey MyDPPropertyKey = DependencyProperty.RegisterReadOnly (...); public static readonly DependencyProperty MyDPProperty = MyDPPropertyKey.DependencyProperty; objeto público MyDP { \t get {return (object) GetValue (MyDPProperty); } \t private set {SetValue (MyDPPropertyKey, value); } } –

4

El problema es que CollectionViewSource.GetDefaultView(object) siempre devolverá la misma instancia ICollectionView para una fuente determinada, y esto es lo que cualquier extensión ItemsControl usará al mostrar esa fuente.

Usted puede evitar esto mediante la creación de una nueva instancia de ICollectionView que será utilizado por cada control que desea ser capaz de filtrar de forma independiente la colección, y luego explícitamente la propiedad vinculante ItemsSource de cada control a esa vista específica. El tipo de ICollectionView necesario dependería de su escenario, pero ListCollectionView es generalmente apropiado.

Cuestiones relacionadas