开发者

Explicitly using TextBlock in Label's Content makes ContentPresenter behave strangely

I have a custom ControlTemplate with double ContentPresenters. 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:

Explicitly using TextBlock in Label's Content makes ContentPresenter behave strangely

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, a TextBlock is generated for the string at each ContentPresenter.
  • When you set a TextBlock directly as Content for a Label, it will end up where you have the ContentPresenter, but since you only have one TextBlock, 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();
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜