Стиль в DataTemplate применяется только к последнему элементу в ItemsControl? - PullRequest
11 голосов
/ 02 марта 2011

В приведенном ниже XAML у меня есть ItemsControl, который имеет три объекта DataObject.
Я использую шаблон данных для отображения объектов DataObject в виде кнопок с символом «X».
Кнопка использует стиль для установки своего содержимого.

Если значение Setter.Value равно "X", все отлично работает!
Однако, если я изменю значение Setter.Value на TextBlock, TextProperty которого равно "X", X отображается только напоследняя кнопка (третий объект DataObject) и первые две кнопки пусты.

Это ошибка, или кто-нибудь может объяснить, почему это происходит?

Примечание 1) Это надуманный пример, позволяющий локализовать возникшую проблему.
Примечание2) Я поместил в код обе опции Setter.Value, чтобы вы могли воспроизвести как успешные, так и неудачные случаи, просто закомментировав один из них.
Примечание 3) Похоже, эта проблема характерна только для Setters дляСвойство «Контент».Если я использую Setter для свойства Background, он корректно применяется ко всем объектам DataObject.

<Grid>
    <Grid.Resources>
        <Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Content">
                <!--<Setter.Value>X</Setter.Value>-->
                <Setter.Value><TextBlock Text="X" /></Setter.Value>
            </Setter>
            <Setter Property="Background">
                <Setter.Value>
                    <SolidColorBrush Color="Red" />
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <ItemsControl>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type DataObject}">
                <Button Height="24" Width="24" Style="{StaticResource myButtonStyle}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.Items>
            <DataObject />
            <DataObject />
            <DataObject />
        </ItemsControl.Items>
    </ItemsControl>
</Grid>

Решение:

К сожалению, я все еще не могу объяснить, почему Setter «Content» не удаетсяработать со всеми объектами, кроме последнего объекта DataObject, если для Content задан элемент управления, например TextBlock, а не прямой текст.

Однако предложение Дмитрия использовать параметр ContentTemplate вместо Content - оченьприемлемый обходной путь, который все еще допускает многоразовое использование стиля.

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="textBlockWithX">
            <TextBlock Text="X" />
        </DataTemplate>
        <Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="ContentTemplate" Value="{StaticResource textBlockWithX}" />
        </Style>
    </Grid.Resources>
    <ItemsControl>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type DataObject}">
                <Button Height="24" Width="24" Style="{StaticResource myButtonStyle}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.Items>
            <DataObject />
            <DataObject />
            <DataObject />
        </ItemsControl.Items>
    </ItemsControl>
</Grid>

Ответы [ 2 ]

9 голосов
/ 02 января 2012

Ответ на этот вопрос довольно прост, на самом деле каждый визуальный может быть только потомком одного объекта, в отличие от текста, подобного "X", который является просто данными.

Если вы создаетестиль, подобный следующему:

<Style>
    <Setter Property="Content">
        <Setter.Value>
             <TextBlock Text="X"/>
        </Setter.Value>
    </Setter>
<Style>

Только один TextBlock создается для всех экземпляров, к которым применяется стиль, поэтому TextBlock будет "прыгать" в каждом приложении и завершатьсядо последнего элемента.

Если вы установите ContentTemplate, однако вы создаете, поскольку имя подразумевает шаблон, который используется для генерации содержимого независимо для каждого объекта, так что вы в конечном итоге получаетеодин экземпляр на элемент управления, где применяется стиль.

6 голосов
/ 02 марта 2011

Вот рабочий пример:

<Window x:Class="Styles.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Styles"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <Style x:Key="A" TargetType="{x:Type Button}">
                <Style.Setters>
                    <Setter Property="Content" Value="X"></Setter>
                </Style.Setters>
            </Style>
        </Grid.Resources>
        <ItemsControl>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Height="24" Width="24" Style="{StaticResource A}">

                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.Items>
                <DataObject></DataObject>
                <DataObject></DataObject>
                <DataObject></DataObject>
            </ItemsControl.Items>
        </ItemsControl>
    </Grid>

</Window>

Edit1 Doh .. Получил работу, хитрость заключается в использовании ContentTemplate.

<Window x:Class="Styles.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Styles"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <DataTemplate x:Key="A">
                <TextBlock>X</TextBlock>
            </DataTemplate>
        </Grid.Resources>
        <ItemsControl>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Height="24" Width="24" ContentTemplate="{StaticResource A}">

                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.Items>
                <DataObject></DataObject>
                <DataObject></DataObject>
                <DataObject></DataObject>
            </ItemsControl.Items>
        </ItemsControl>
    </Grid>

</Window>

Edit2: образец более сложного ContentTemplate

<Window x:Class="Styles.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Styles"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <DataTemplate x:Key="A">
                <StackPanel Width="30" Orientation="Horizontal">
                    <Grid Background="White" Width="10" Height="10"></Grid>
                    <Grid Background="Blue" Width="10" Height="10"></Grid>
                    <Grid Background="Red" Width="10" Height="10"></Grid>
                </StackPanel>
            </DataTemplate>
        </Grid.Resources>
        <ItemsControl>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Height="24" Width="34" ContentTemplate="{StaticResource A}">

                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.Items>
                <DataObject></DataObject>
                <DataObject></DataObject>
                <DataObject></DataObject>
            </ItemsControl.Items>
        </ItemsControl>
    </Grid>

</Window>
...