Explicitly using TextBlock in Label's Content makes ContentPresenter behave strangely
I have a custom ControlTemplate
with double ContentPresenter
s. The template is applied to a Label
. When I set "Random octopus" (just text) as Label's Content, it works exactly as expected. When I set "<TextBlock>Random octopus</TextBlock>" as the Content, it doesn't work (only one ContentPresenter is visually represented). I use the following code to reproduce the behavior:
<Window x:Class="WeirdTextBlock.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources&开发者_开发问答gt;
<Style TargetType="Label">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border BorderBrush="Red" BorderThickness="1" Padding="2">
<Grid>
<ContentPresenter />
<ContentPresenter Margin="2,2,0,0" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="20" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0">
Random octopus
</Label>
<Label Grid.Row="2">
<TextBlock>Random octopus</TextBlock>
</Label>
</Grid>
</Window>
And here you can see how it looks like:
I thought when you enter just text into Content property, it gets wrapped by TextBlock, so why exactly is the second Label's visual representation different from the first one? And how to make the second Label behave correctly (make it look like the first Label, but only by modifying the template)? Thanks!
The underlying problem here is you're attempting to place a visual (the TextBlock
) in two different places at once. A visual can only have a single parent, so one of the content presenters "wins" and the other won't have any content.
If all you want to do is have a visual copy of the TextBlock
then use a VisualBrush
.
The difference is...
- When you set a string as Content for a
Label
, aTextBlock
is generated for the string at eachContentPresenter
. - When you set a
TextBlock
directly asContent
for aLabel
, it will end up where you have theContentPresenter
, but since you only have oneTextBlock
, it can only be at one place at a time.
Update
<Style TargetType="Label">
<Style.Resources>
<local:TypeOfConverter x:Key="TypeOfConverter"/>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Transparent"/>
</Style>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border BorderBrush="Red" BorderThickness="1" Padding="2">
<Grid>
<ContentPresenter Name="content" Grid.ZIndex="2"/>
<ContentPresenter Name="secondContent" Grid.ZIndex="1" Margin="2,2,0,0" Visibility="Collapsed"/>
<Border Grid.ZIndex="1">
<Border.RenderTransform>
<TranslateTransform X="2" Y="2"/>
</Border.RenderTransform>
<Border.Background>
<VisualBrush Visual="{Binding ElementName=content, Path=Content}"/>
</Border.Background>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Path=Content,
Converter={StaticResource TypeOfConverter}}"
Value="{x:Type sys:String}">
<Setter TargetName="secondContent" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TypeOfConverter
public class TypeOfConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value == null) ? null : value.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
精彩评论