2010-10-01 17 views
7

Puedo usar una plantilla de elemento dentro de ItemsControl para representar elementos en un formato específico. Sin embargo, si uno de los elementos dentro de ItemsControl resulta ser, por ejemplo, un TextBox, ese TextBox se representa en lugar de una instancia de ItemsTemplate. Por lo que puedo decir, esto es cierto para cualquier FrameworkElement. ¿Es este el comportamiento previsto para un ItemsControl, o estoy haciendo algo incorrectamente?¿Por qué ItemsControl no utiliza My ItemTemplate?

Un ejemplo:

<ItemsControl> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Grid Margin="5"> 
     <Rectangle Fill="Blue" Height="20" Width="20" /> 
     </Grid> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    <ItemsControl.Items> 
    <sys:Object /> 
    <TextBox /> 
    <sys:Object /> 
    <Rectangle Fill="Red" Height="20" Width="20" /> 
    </ItemsControl.Items> 
</ItemsControl> 

me esperaba esto para visualizar cuatro rectángulos azules. Pensé que cada vez que se definiera una plantilla de elemento, cada elemento de la colección se representaría como una instancia de la plantilla. Sin embargo, en este caso se representa lo siguiente: un rectángulo azul seguido de un cuadro de texto seguido de un rectángulo azul seguido de un rectángulo rojo.

+0

supongo que esto está destinado comportamiento, y es destinado a permitir a los desarrolladores la posibilidad de agregar controles especiales de uso único. Por ejemplo, podría usar esto para agregar un Botón a un ComboBox que borre la selección, o podría poner un TextBox en un ListBox que filtre la colección especificada por ItemsSource. Me encantaría escuchar que alguien tiene alguna respuesta oficial para este comportamiento porque me pareció contraintuitivo el uso de una plantilla de elemento. – Drew

+0

Gran pregunta y excelente respuesta de Anthony, gracias chicos. – Golvellius

Respuesta

12

El ItemsControl tiene un miembro protegido IsItemItsOwnContainerOverride que se pasa un objeto de la colección de artículos y devuelve true si ese objeto se puede añadir directamente al panel de artículos sin un contenedor generado (y de ese modo ser templated).

La implementación base devuelve verdadero para cualquier objeto que se derive de UIElement.

Para obtener el comportamiento que esperaría, necesitaría heredar de ItemsControl y anular este método y hacer que siempre devuelva falso. Desafortunadamente, eso no es el final del asunto. La implementación predeterminada de PrepareContainerForItemOverride todavía no asigna el ItemTemplate al envase si el artículo es un UIElement Así que hay que reemplazar este método así: -

protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return false; 
    } 


    protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
    { 
     base.PrepareContainerForItemOverride(element, item); 
     ((ContentPresenter)element).ContentTemplate = ItemTemplate; 
    } 
+1

A partir de 2015, es posible que hayan corregido la segunda parte. Con WPF en .NET 4.5.1, si devuelvo 'false' para' IsItemItsOwnContainerOverride, 'entonces la plantilla parece estar configurada en el contenedor de elementos. –

2

Solo estoy especulando aquí, pero apostaría que es un comportamiento que vive dentro del ItemContainerGenerator. Apostaría que el ItemContainerGenerator mira un artículo, y si es un UIElement dice, "genial, el contenedor del artículo ha sido generado, lo devolveré" y si no lo está, dice: "Será mejor que genere un contenedor para este artículo. ¿Dónde está el DataTemplate? "

Cuestiones relacionadas