Следующее похоже на то, что я пытаюсь достичь. Однако я получаю сообщение об ошибке

Недопустимое значение 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>
21
Travis Heseman 22 Авг 2010 в 20:58

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">
43
Jogge 19 Июн 2019 в 21:43
Работает плавно! Я пытался сделать все это с помощью XAML, и всего несколько строк кода для создания класса делают все это счастливым, аккуратным и чистым.
 – 
Travis Heseman
22 Авг 2010 в 21:30
1
«Если вы добавили элемент, отличный от UIElement, этот установщик установит свойство Control.Template для ContentPresenter, что будет выполнено успешно, но не окажет никакого эффекта». - Я долго искал, прежде чем нашел этот совет!
 – 
Daniel
24 Окт 2011 в 14:04

Также, если вы хотите сделать все это только с помощью 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 (выбор элементов), и при использовании этой техники выбор элементов больше не работает.

3
000 19 Сен 2011 в 07:32