I was looking at this question, and discovered that binding Label.Content
to a non-string value will apply an implicit TextBlock
style, however binding to a string does not.
Here's some sample code to reproduce the problem:
<Window.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Margin" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding SomeString}" Background="Red"/>
<Label Content="{Binding SomeDecimal}" Background="Green"/>
</StackPanel>
</Grid>
Where the code for the bound values are
SomeDecimal = 50;
SomeString = SomeDecimal.ToString();
And the end result looks like this, with the Margin
property from the implicit TextBlock style getting applied to the Label bound to a non-string only:
Both labels get rendered as
<Label>
<Border>
<ContentPresenter>
<TextBlock />
</ContentPresenter>
</Border>
</Label>
When I check out the VisualTree with Snoop, I can see that it looks exactly the same for both elements, except the 2nd TextBlock applies the Margin from the implicit style, while the first does not.
I've used Blend to pull out a copy of the default Label Template, but don't see anything strange there, and when I apply the template to both my labels, the same thing happens.
<Label.Template>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Label.Template>
It should also be noted that setting a default ContentTemplate
to a TextBlock
does make both items render without the implicit style, so it must have something to do with when WPF tries to render a non-string value as part of the UI.
<Window.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="TemplatedStyle" TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding }"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Margin" Value="10"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding SomeString}" Background="Red"/>
<Label Content="{Binding SomeDecimal}" Background="Green"/>
<Label Content="{Binding SomeString}" Background="Red"
Style="{StaticResource TemplatedStyle}"/>
<Label Content="{Binding SomeDecimal}" Background="Green"
Style="{StaticResource TemplatedStyle}"/>
</StackPanel>
</Grid>
What is the logic that causes a non-string inserted into the UI to be drawn using an implicit TextBlock style, but a string inserted into the UI does not? And where does this occur at?