2010-08-22 1 views
19

Следующее похоже на то, что я пытаюсь выполнить. Тем не менее, я получаю ошибкуУказать ControlTemplate для ItemsControl.ItemContainerStyle

Недопустимое значение PropertyDescriptor.

на шаблоне Setter. Я подозреваю, что это потому, что я не указал TargetType для Style; однако я не знаю тип контейнера для 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> 

ответ

35

Вы можете квалифицироваться имя свойства с именем типа:

<Setter Property="Control.Template"> 

Контейнер для ItemsControl обычно является ContentPresenter, но если ребенок является UIElement, то он не будет использовать контейнер. В этом случае все дети являются элементами управления, поэтому ItemContainerStyle будет применяться к ним напрямую. Если вы добавили элемент, отличный от UIElement, этот установщик установит свойство Control.Template в ContentPresenter, которое будет успешным, но не будет иметь эффекта.

На самом деле, похоже, что вы хотите обернуть каждого ребенка в контейнер, даже если они уже являются UIElement. Для этого вам нужно будет использовать подкласс ItemsControl. Вы можете использовать существующий, такой как ListBox, или вы можете подклассифицировать ItemsControl и переопределить GetContainerForItemOverride и IsItemItsOwnContainerOverride, чтобы обернуть элементы в свой собственный контейнер. Вы можете обернуть их в ContentControl, а затем использовать это как TargetType для стиля.

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

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

Вам также потребуется установить TargetType на ControlTemplate, так что ContentPresenter будет связываться с контентной собственности:

<ControlTemplate TargetType="ContentControl"> 
+0

Работы плавно! Я пытался сделать все это с помощью XAML, и всего несколько строк кода для получения класса делают его счастливым, аккуратным и чистым. –

+1

«Если вы добавили элемент, отличный от UIElement, этот установщик установит свойство Control.Template в ContentPresenter, что будет успешным, но не будет иметь эффекта». - Я искал веки, прежде чем нашел этот совет! – Daniel

2

Кроме того, если вы хотите, чтобы сделать все это с XAML вы можете просто использовать ListBox вместо ItemsControl и определить стиль для 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> 

Обратите внимание, что, поскольку я использую ListBox контейнер ListBoxItem (Как правило, контейнер для WP F в управление списка по умолчанию всегда называется деталь) так мы создаем стиль для ListBoxItem:

<Style TargetType="ListBoxItem"> 

Затем мы создаем новый ControlTemplate для ListBoxItem. Обратите внимание, что ContentPresenter не используется, как всегда, в статьях и учебниках, вам необходимо привязать шаблон к свойству Content свойства ListBoxItem, чтобы он отображал содержимое этого элемента.

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

У меня была такая же проблема и исправлена ​​ее так. Мне не нужны некоторые функции ListBox (выбор элементов), и с помощью этой техники выбор элемента больше не работает.