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).
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);
}
}
<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.