DataTemplate 中的样式仅应用于 ItemsControl 中的最后一项?
在下面的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实际上,这个问题的答案相当简单,每个视觉对象只能是一个对象的子对象,不像
“X”
这样的文本只是数据。如果您创建这样的样式:
为应用该样式的所有实例仅创建一个
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:
Only one
TextBlock
is created for all instances on which the style is applied, so theTextBlock
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.这是一个工作示例:
Edit1 Doh..让它工作,技巧是使用 ContentTemplate。
Edit2:更复杂的 ContentTemplate 示例:
Here's a working sample:
Edit1 Doh.. Got it working, the trick is to use ContentTemplate.
Edit2: A sample of more complex ContentTemplate: