简体   繁体   中英

How to display the base control in a WPF custom control

I want to extend a TextBox control to include a Label, where the Label gets its Content from my custom control's Label property and automatically attaches to the TextBox. (This is a dumbed down example for learning purposes).

LabeledTextBox.cs

public class LabeledTextBox : TextBox
{
    static LabeledTextBox() =>
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledTextBox),
            new FrameworkPropertyMetadata(typeof(LabeledTextBox)));

    public static readonly DependencyProperty LabelProperty =
        DependencyProperty.Register("Label", typeof(string), typeof(LabeledTextBox));

    public string Label
    {
        get => (string)GetValue(LabelProperty);
        set => SetValue(LabelProperty, value);
    }
}

Themes/Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyExample">

    <Style TargetType="{x:Type local:LabeledTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
                    <StackPanel Orientation="Vertical">
                        <Label Margin="0 0 0 4" Content="{TemplateBinding Label}" Target="{Binding ElementName=tbThis}" />

                        <!-- This doesn't work -->
                        <ContentPresenter x:Name="tbThis" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

I can't figure out how to display the TextBox base class. I've searched through SO and the first several links in Google. It looks like what I should use is <ContentPresenter /> but it's simply not showing up. I also tried several variants of setting ContentPresenter.ContentSource within the XAML to no avail.

I know I could add a TextBox in the ControlTemplate, but that would mean either losing all the properties of the inherited TextBox or needing to attach them all manually, which defeats the entire purpose of using a custom control over a UserControl .

Simply bind Target to TemplatedParent :

<ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
    <StackPanel>
        <Label Target="{Binding RelativeSource={RelativeSource TemplatedParent}}" Content="{TemplateBinding Label}"/>
        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
            <ScrollViewer Focusable="False" x:Name="PART_ContentHost" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
        </Border>
    </StackPanel>
</ControlTemplate>

You need to access the visual element using PART_ContentHost WPF magic :)

Here is how it would look:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyExample">

    <Style TargetType="{x:Type local:LabeledTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
                    <StackPanel Orientation="Vertical">
                        <Label Margin="0 0 0 4" Content="{TemplateBinding Label}" Target="{Binding ElementName=tbThis}" />

                                <ScrollViewer x:Name="PART_ContentHost"
                                              HorizontalAlignment="Stretch"
                                              VerticalAlignment="Center"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM