DataTemplate中的样式是否仅应用于ItemsControl中的最后一项?

时间:2021-01-29 23:00:05

In the XAML below, I have an ItemsControl that has three DataObjects.
I use a DataTemplate to display DataObjects as Buttons with an "X" on them.
The Button uses a Style to set its Content.

在下面的XAML中,我有一个ItemsControl,它有三个DataObjects。我使用DataTemplate将DataObjects显示为带有“X”的按钮。 Button使用样式设置其内容。

If the Setter.Value is "X", everything works great!
However, if I change the Setter.Value to a TextBlock whose TextProperty is "X", the X only appears on the last Button (the third DataObject) and the first two Buttons are empty.

如果Setter.Value为“X”,一切都很棒!但是,如果我将Setter.Value更改为TextProperty为“X”的TextBlock,则X仅出现在最后一个Button(第三个DataObject)上,前两个按钮为空。

Is this a bug, or can anybody explain why this happens?

这是一个错误,还是任何人都能解释为什么会这样?

Note 1) This is a contrived example to isolate the problem being encountered.
Note 2) I've put both Setter.Value options in the code so you can reproduce both the successful and unsuccessful cases just by having one of them commented out.
Note 3) It appears, this problem is specific to Setters for the 'Content' property. If I use a Setter for the Background property, it correctly applies to all of the DataObjects.

注1)这是一个人为的例子来隔离遇到的问题。注2)我已将两个Setter.Value选项放在代码中,这样您只需将其中一个注释掉即可重现成功案例和不成功案例。注3)看来,这个问题特定于'内容'属性的Setters。如果我使用Setter作为Background属性,它将正确应用于所有DataObjects。

<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>

Solution:

Unfortunately, I still cannot explain why the 'Content' Setter fails to work on all but the last DataObject when the Content is set to be a control such as a TextBlock rather than straight text.

However, Dmitry's suggestion of using setting the 'ContentTemplate' instead of 'Content' is a very acceptable workaround that still allows for a re-usable Style.

但是,Dmitry建议使用“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 个解决方案

#1


6  

Here's a working sample:

这是一个工作样本:

<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.. Got it working, the trick is to use ContentTemplate.

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: A sample of more complex ContentTemplate:

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>

#2


7  

The answer to this is rather simple actually, every visual can only be the child of one object, unlike text like "X" which is just data.

对此的答案实际上相当简单,每个视觉只能是一个对象的子节点,而不像“X”这样的文本只是数据。

If you create a style like this:

如果您创建这样的样式:

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

Only one TextBlock is created for all instances on which the style is applied, so the TextBlock will "jump" on every application and end up at the last item.

仅为应用了样式的所有实例创建一个TextBlock,因此TextBlock将“跳转”到每个应用程序并最终到达最后一个项目。

If you set the ContentTemplate however you create as the name implies a template which is used to generate the content independenctly for every object so you end up with one instance per control where the style applies.

如果您设置ContentTemplate但是您创建的名称意味着一个模板,该模板用于为每个对象独立生成内容,因此您最终会在每个控件应用样式时使用一个实例。

#1


6  

Here's a working sample:

这是一个工作样本:

<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.. Got it working, the trick is to use ContentTemplate.

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: A sample of more complex ContentTemplate:

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>

#2


7  

The answer to this is rather simple actually, every visual can only be the child of one object, unlike text like "X" which is just data.

对此的答案实际上相当简单,每个视觉只能是一个对象的子节点,而不像“X”这样的文本只是数据。

If you create a style like this:

如果您创建这样的样式:

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

Only one TextBlock is created for all instances on which the style is applied, so the TextBlock will "jump" on every application and end up at the last item.

仅为应用了样式的所有实例创建一个TextBlock,因此TextBlock将“跳转”到每个应用程序并最终到达最后一个项目。

If you set the ContentTemplate however you create as the name implies a template which is used to generate the content independenctly for every object so you end up with one instance per control where the style applies.

如果您设置ContentTemplate但是您创建的名称意味着一个模板,该模板用于为每个对象独立生成内容,因此您最终会在每个控件应用样式时使用一个实例。