Следующее похоже на то, что я пытаюсь достичь. Однако я получаю сообщение об ошибке
Недопустимое значение 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
для 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">
Также, если вы хотите сделать все это только с помощью 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 (выбор элементов), и при использовании этой техники выбор элементов больше не работает.
Похожие вопросы
Связанные вопросы
Новые вопросы
wpf
Windows Presentation Foundation, или WPF, является подсистемой для визуализации пользовательских интерфейсов в приложениях на основе Windows.