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