Укажите 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>
2 ответа
Вы можете указать имя свойства с именем типа:
<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 связывался со свойством Content:
<ControlTemplate TargetType="ContentControl">
Также, если вы хотите сделать все это только с 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(обычно контейнер для элемента управления списком WPF по умолчанию всегда называется Item), поэтому мы создаем стиль для ListBoxItem:
<Style TargetType="ListBoxItem">
Затем мы создаем новый ControlTemplate для ListBoxItem. Обратите внимание, что ContentPresenter не используется, как это всегда появляется в статьях и руководствах, вам необходимо привязать шаблон к свойству Content объекта ListBoxItem, чтобы он отображал содержимое этого элемента.
<ContentPresenter Content="{TemplateBinding Content}" />
У меня была такая же проблема, и я решил ее так. Мне не нужны некоторые функции ListBox (выбор элементов), и с помощью этой техники выбор элементов больше не работает.