2010-08-22 17 views
19

Quanto segue è simile a quello che sto cercando di realizzare. Tuttavia, viene visualizzato l'erroreSpecificare ControlTemplate per ItemsControl.ItemContainerStyle

Valore PropertyDescriptor non valido.

sul modello Setter. Sospetto che sia perché non ho specificato un TargetType per il Style; tuttavia, non conosco il tipo di contenitore per 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> 

risposta

35

È possibile qualificare il nome della proprietà con il nome del tipo:

<Setter Property="Control.Template"> 

Il contenitore per ItemsControl è normalmente un ContentPresenter, ma se il bambino è un UIElement allora non utilizzare un contenitore. In questo caso, tutti i bambini sono Controlli, quindi ItemContainerStyle verrà applicato direttamente a loro. Se hai aggiunto un elemento diverso da un UIElement, il setter impostava la proprietà Control.Template su ContentPresenter, che avrebbe avuto successo ma non avrebbe avuto alcun effetto.

In realtà, sembra che quello che vuoi sia racchiudere ogni bambino in un contenitore, anche se sono già un UIElement. Per fare ciò, dovrai usare una sottoclasse di ItemsControl. È possibile utilizzare uno esistente come ListBox o sottoclasse ItemsControl e sovrascrivere GetContainerForItemOverride e IsItemItsOwnContainerOverride per disporre gli elementi nel proprio contenitore. Potresti avvolgerli in un ContentControl e utilizzarli come TargetType per lo stile.

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

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

Sarà inoltre necessario impostare la TargetType sul ControlTemplate in modo che il ContentPresenter si legherà alla proprietà Content:

<ControlTemplate TargetType="ContentControl"> 
+0

Funziona bene! Stavo cercando di fare tutto con XAML, e solo poche righe di codice per ottenere una classe rende tutto felice, pulito e pulito. –

+1

"Se hai aggiunto un elemento diverso da un UIElement, il setter impostava la proprietà Control.Template su ContentPresenter, che avrebbe avuto successo ma non avrebbe avuto alcun effetto." - Ho cercato per anni prima di trovare questo suggerimento! – Daniel

2

Inoltre, se si desidera solo fare tutto con XAML è possibile è sufficiente utilizzare ListBox al posto di ItemsControl e definire uno stile per 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> 

noti che perché sto usando ListBox il contenitore è ListBoxItem (generalmente il contenitore per WP Controllo elenco predefinito di F viene sempre chiamato la voce) e quindi si crea uno stile per ListBoxItem:

<Style TargetType="ListBoxItem"> 

viene creato un nuovo ControlTemplate per ListBoxItem. Si noti che ContentPresenter non viene utilizzato come appare sempre negli articoli e nelle esercitazioni, è necessario associarlo a modello alla proprietà Content di ListBoxItem, in modo che mostri il contenuto per quell'elemento.

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

Ho appena avuto lo stesso problema e l'ho risolto in questo modo. Non desidero alcune funzionalità di ListBox (selezione degli oggetti) e utilizzando questa tecnica la selezione degli oggetti non funziona più.

Problemi correlati