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

发布于 2024-10-19 16:55:49 字数 2880 浏览 2 评论 0原文

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

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

这是一个错误吗?或者有人可以解释为什么会发生这种情况吗?

注意 1)这是一个人为的示例,用于隔离遇到的问题。
注 2)我已将两个 Setter.Value 选项放入代码中,这样您只需注释掉其中一个即可重现成功和不成功的案例。
注 3)看来,这个问题是针对“Content”属性的 Setters 特有的。如果我对背景属性使用 Setter,它会正确应用于所有 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>

解决方案:

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.

但是,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>

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.

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.

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.

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼藏柔 2024-10-26 16:55:49

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

如果您创建这样的样式:

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

为应用该样式的所有实例仅创建一个 TextBlock,因此 TextBlock 将“跳转” " 在每个应用程序上,并最终出现在最后一项。

如果您设置了 ContentTemplate,但顾名思义,您创建了一个模板,该模板用于为每个对象独立生成内容,因此最终每个控件都会有一个实例,其中风格适用。

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.

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.

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.

_失温 2024-10-26 16:55:49

这是一个工作示例:

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

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.

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

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文