I am trying make my own version of a control, say a TextBox, to which I want to add some custom UI. I am want to inherit from this class, so that the user can still call my special text box in the same way he would call a regular one. I have got the following:
// MySpecialTextBox.cs
public class MySpecialTextBox : TextBox
{
static MySpecialTextBox () { }
/* Some special properties */
}
In XAML:
<Style TargetType="{x:Type MySpecialTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MySpecialTextBox}">
<StackPanel>
<Rectangle Width="100" Height="3" Fill="Pink" /> <!-- My own fancy lay-out -->
<TextBox Text="{TemplateBinding Text}"/> <!-- This text box should 'inherit' ALL the properties from the caller -->
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My problem here is that now, the TextBox only gets the properties you explicitly set in this template, in this case, only Text. I would like to also bind to Background, Foreground, and every other possible property. Obviously I could do something like:
<ControlTemplate TargetType="{x:Type MySpecialTextBox}">
<StackPanel>
<Rectangle Width="100" Height="3" Fill="Pink" />
<TextBox Text="{TemplateBinding Text}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
AcceptsReturn="{TemplateBinding AcceptsReturn}"
AllowDrop="{TemplateBinding AllowDrop}"
<!-- ETCETERA -->
/>
</StackPanel>
</ControlTemplate>
listing all properties, but that feels horribly inefficient. Is there a way to bind to the entire parent in one go?
It is not a good idea to place another TextBox element in a template for another TextBox. What you should do is always edit the default template for a control when you are overriding its template.
So, in the default template for a TextBox you will find the following element:
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
This border is responsible for drawing the TextBox. If you use this part instead of your inner TextBox you will have all other TextBox properties "Inherited".
Edit:
The full template should be:
<Style TargetType="{x:Type my:MySpecialTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type my:MySpecialTextBox}">
<StackPanel>
<Rectangle Width="100" Height="3" Fill="Pink" />
<!-- My own fancy lay-out -->
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
A TemplateBinding is an optimized form of a standard Binding and roughly equivalent to using a Binding with the RelativeSource property set to RelativeSource.TemplatedParent. As such and like standard Bindings, can only be set on a single property. From the TemplateBindingExtension Class page on MSDN:
You use
TemplateBindingin template to bind to a value on the control the template is applied to.
From the TemplateBinding Markup Extension page on MSDN:
...
TemplateBindinghas only one settable property...
This means that we cannot supply more than one property name to it and so it only works with a single property. Unfortunately, there is no convenient SuperTemplateBinding that affects all properties, but even if there were, I can't imagine any easy way to map which properties should bind to which template properties. The answer is therefore 'No, there is no shortcut to inheriting property values from a templated parent control'.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With