【问题标题】:Style within DataTemplate is only being applied to the last item in ItemsControl?DataTemplate 中的样式仅应用于 ItemsControl 中的最后一项?
【发布时间】:2011-07-07 10:08:00
【问题描述】:

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

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

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

注 1)这是一个人为的示例,用于隔离遇到的问题。
注 2)我已将两个 Setter.Value 选项都放在代码中,因此您只需将其中一个注释掉即可重现成功和不成功的案例。
注 3)看来,这个问题是特定于“内容”属性的设置器。如果我为 Background 属性使用 Setter,它会正确应用于所有 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>

解决办法:

不幸的是,我仍然无法解释为什么当 Content 设置为控件(例如 TextBlock)而不是纯文本时,“Content”Setter 无法在除最后一个 DataObject 之外的所有数据对象上工作。

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

【问题讨论】:

  • 嗨,您显然知道罪魁祸首是 DataTemplate 中的样式,一旦您将 Content 用作普通属性,一切都会开始工作。
  • 在这个人为/简化的示例中肯定有一个解决方法。但我不确定我理解为什么这是“设计”。将 Content Setter 的值设置为“X”有效...但将其设置为 TextBlock 仅适用于最后一项...对我来说似乎很奇怪。

标签: wpf xaml styles datatemplate itemscontrol


【解决方案1】:

这个问题的答案其实很简单,每个visual只能是一个对象的子对象,不像"X"这样的文本只是数据。

如果你创建这样的样式:

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

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

如果您设置ContentTemplate,但是您创建的顾名思义就是一个模板,该模板用于为每个对象独立地生成内容,因此您最终每个控件都有一个应用样式的实例.

【讨论】:

    【解决方案2】:

    这是一个工作示例:

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

    【讨论】:

    • 我认为我没有使用隐式样式。我什至在示例代码中都没有资源部分。我正在明确设置样式。
    • 嗨,实际上,
    • 我明确设置 ,这不在资源部分。我可以取出 TargetType="{x:Type Button}",并将我的 Setter 更改为 Property="Button.Content",我仍然得到相同的结果。 (我只使用 TargetType 来获取智能感知)。
    • 我在我的问题中添加了第二个示例,以提供一个没有隐式样式的示例。如果我的理解是正确的,那么在我的 Style 中有一个 x:Key 不能被认为是一种隐式风格。我仍然看到没有隐式样式的问题。
    • 对不起,我认为它现在已经解决了 - 您不必设置整个模板,因为似乎有一个专用的 rproperty - ContentTemplate。我已经更新了我的答案以包含实际的解决方案。您可以使用创建任何复杂程度的模板。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 2013-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多