2010-08-22 25 views
19

Lo siguiente es similar a lo que estoy tratando de lograr. Sin embargo, obtengo el errorEspecifique ControlTemplate para ItemsControl.ItemContainerStyle

Valor invalido de PropertyDescriptor.

en la plantilla Setter. Sospecho que es porque no especifique un TargetType para el Style; sin embargo, no conozco el tipo de contenedor para ItemsControl.

<ItemsControl> 
    <ItemsControl.ItemContainerStyle> 
     <Style> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate> 
         <StackPanel> 
          <TextBlock Text="Some Content Here" /> 
          <ContentPresenter /> 
          <Button Content="Edit" /> 
         </StackPanel> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
    <!-- heterogenous controls --> 
    <ItemsControl.Items> 
     <Button Content="Content 1" /> 
     <TextBox Text="Content 2" /> 
     <Label Content="Content 3" /> 
    </ItemsControl.Items> 
</ItemsControl> 

Respuesta

35

Puede calificar el nombre de propiedad con el nombre del tipo:

<Setter Property="Control.Template"> 

El contenedor de ItemsControl es normalmente un ContentPresenter, pero si el niño es un UIElement entonces no va a utilizar una envase. En este caso, todos los hijos son controles, por lo que ItemContainerStyle se aplicará a ellos directamente. Si agrega un elemento que no sea un UIElement, ese setter establecería la propiedad Control.Template en el ContentPresenter, que tendría éxito pero no tendría ningún efecto.

En realidad, parece que lo que desea es envolver a cada niño en un contenedor, incluso si ya son un UIElement. Para hacer eso, tendrá que usar una subclase de ItemsControl. Puede usar uno existente como ListBox, o puede crear una subclase de ItemsControl y anular GetContainerForItemOverride y IsItemItsOwnContainerOverride para envolver los elementos en su propio contenedor. Podría envolverlos en ContentControl y luego usarlos como TargetType for the Style.

public class CustomItemsControl 
    : ItemsControl 
{ 
    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new ContentControl(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     // Even wrap other ContentControls 
     return false; 
    } 
} 

También tendrá que configurar el TargetType en el ControlTemplate para que el ContentPresenter se unirá a la propiedad del contenido:

<ControlTemplate TargetType="ContentControl"> 
+0

¡Trabaja maravillosamente! Intentaba hacer todo esto con XAML, y solo unas pocas líneas de código para obtener una clase lo hacen todo feliz, ordenado y limpio. –

+1

"Si agrega un elemento que no sea un UIElement, ese setter establecería la propiedad Control.Template en ContentPresenter, que tendría éxito pero no tendría ningún efecto". - ¡Busqué edades antes de encontrar este consejo! – Daniel

2

Además, si sólo desea hacer todo con XAML que pueda basta con utilizar ListBox en lugar de ItemsControl y definir un estilo para ListBoxItem:

 <ListBox ItemsSource="{Binding Elements.ListViewModels}"> 
     <ListBox.Resources> 
      <Style TargetType="ListBoxItem"> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="ListBoxItem"> 
          <StackPanel> 
           <TextBlock>Some Content Here</TextBlock> 
           <ContentPresenter Content="{TemplateBinding Content}" /> 
           <Button>Edit</Button> 
          </StackPanel> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 
     </ListBox.Resources> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel /> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 

Tenga en cuenta que debido a que estoy usando ListBox el contenedor es ListBoxItem (en general, el contenedor para WP control de lista por defecto de F siempre se denomina el artículo) por lo que crear un estilo para ListBoxItem:

<Style TargetType="ListBoxItem"> 

entonces se crea una nueva ControlTemplate para ListBoxItem. Tenga en cuenta que ContentPresenter no se utiliza, ya que siempre aparece en los artículos y tutoriales, necesita vincular la plantilla a la propiedad del contenido de ListBoxItem, por lo que mostrará el contenido de ese elemento.

<ContentPresenter Content="{TemplateBinding Content}" /> 

Acabo de tener el mismo problema y lo solucioné de esta manera. No quiero algunas funcionalidades de ListBox (selección de elementos) y al usar esta técnica la selección de elementos ya no funciona.

Cuestiones relacionadas