Укажите ControlTemplate для ItemsControl.ItemContainerStyle
Следующее похоже на то, что я пытаюсь выполнить. Однако я получаю сообщение об ошибке
Недопустимое значение PropertyDescriptor.
на шаблоне Setter
. Я подозреваю это, потому что я не указал <<21 > для 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>
Ответы
Ответ 1
Вы можете указать имя свойства с именем типа:
<Setter Property="Control.Template">
Контейнер для ItemsControl
обычно является ContentPresenter
, но если дочерний элемент является UIElement
он не будет использовать контейнер. В этом случае все дочерние элементы являются ItemContainerStyle
управления, поэтому ItemContainerStyle
будет применяться к ним напрямую. Если вы добавите элемент, отличный от UIElement
, этот установщик установит свойство Control.Template
для ContentPresenter
, что будет успешно выполнено, но не будет иметь никакого эффекта.
На самом деле, звучит так, как будто вы хотите заключить каждого дочернего элемента в контейнер, даже если он уже является UIElement
. Для этого вам нужно будет использовать подкласс ItemsControl
. Вы можете использовать существующий, например ListBox
, или GetContainerForItemOverride
подкласс ItemsControl
и переопределить GetContainerForItemOverride
и IsItemItsOwnContainerOverride
чтобы обернуть элементы в вашем собственном контейнере. Вы можете обернуть их в ContentControl
а затем использовать его в качестве TargetType
для Style
.
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">
Ответ 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 (обычно контейнер для элемента управления списком по умолчанию WPF всегда называется Item), поэтому мы создаем стиль для ListBoxItem:
<Style TargetType="ListBoxItem">
Затем мы создаем новый элемент ControlTemplate для ListBoxItem. Обратите внимание, что ContentPresenter не используется, поскольку он всегда появляется в статьях и учебниках, вам необходимо привязать шаблон к свойству Content свойства ListBoxItem, чтобы он отображал содержимое для этого элемента.
<ContentPresenter Content="{TemplateBinding Content}" />
У меня была такая же проблема, и я исправил ее таким образом. Мне не нужны некоторые функции ListBox (выбор элементов), и с помощью этой техники выбор элемента больше не работает.