WPF ControlTemplate: How to provide a default value for TemplateBinding?

25.4k views Asked by At

I am writing a WPF control that subclasses a Button. I then provide a default style in Themes\generic.xaml, that looks like this (simplified):

<Style TargetType="{x:Type WPFControls:MyButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type WPFControls:MyButton}">
                <Button 
                    x:Name="PART_Button"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I would like the user to have the opportunity to change the control's background, but if he doesn't, I'd like to provide default value. How do I do it?

When I do it like in the posted code, the Background and BorderBrush is null (= nonexistent) unless user explicitly specifies them (which effectively forces user to always provide some value), but the standard windows controls (like Button) provide a default look, that can still be customized by user. How to do this in my control?

Thank you!

Solution by Michael Morton:

You can provide defaults as setters in style:

<Style TargetType="{x:Type TestTemplate:MyButton}">
    <Setter Property="Background" Value="Red" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TestTemplate:MyButton}">
                <Button 
                    x:Name="PART_Button"
                    IsEnabled="{TemplateBinding IsEnabled}"
                    Content="{TemplateBinding Content}"
                    Background="{TemplateBinding Background}"
                    />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Usage:

<StackPanel>
    <TestTemplate:MyButton Background="Blue">Explicitly blue</TestTemplate:MyButton>
    <TestTemplate:MyButton>Naturally red</TestTemplate:MyButton>
</StackPanel>
4

There are 4 answers

1
Mara Morton On BEST ANSWER

You can just define setters on your style for the two properties in question.

For example, some general definitions:

<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#F3F3F3" Offset="0"/>
    <GradientStop Color="#EBEBEB" Offset="0.5"/>
    <GradientStop Color="#DDDDDD" Offset="0.5"/>
    <GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>

<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>

Then, in your style definition:

<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}" />
1
Aran Mulholland On

When you declare a dependency property for your controls you also declare the default as UIPropertyMetadata

this property defaults to Brushes.Red, as you can see in the last line.

  public Brush MyBrush {
     get { return (Brush)GetValue(MyBrushProperty); }
     set { SetValue(MyBrushProperty, value); }
  }

  public static readonly DependencyProperty MyBrushProperty =
      DependencyProperty.Register("MyBrush", typeof(Brush), typeof(MyQsFeature), new UIPropertyMetadata(Brushes.Red));

the other way you could do it is by setting the default colour in the constructor of your custom control, as the constructor always gets called before any properties are set by the user if the user fails to set them they would default to yours. In fact they would always get set by you and then any user setting will override yours. This is esp effective if you want to set the properties such as Background that you are not actually creating, the ones that are coming from your the base classes that you are inheriting from.

0
Marcin Wisnicki On

It is also possible to "inherit" default style of the Button element by creating sample instance and referencing its properties:

<Button x:Key="DefaultButton"/>

<Style TargetType="{x:Type TestTemplate:MyButton}">
        <Setter Property="Background"
                Value="{Binding Path=Background, Source={StaticResource DefaultButton}}" />
</Style>
1
Marat Batalandabad On
<Style TargetType="{x:Type WPFControls:MyButton}">
    <Setter Property="Background" Value="Black">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type WPFControls:MyButton}">
                <Button 
                    x:Name="PART_Button"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Pay attention on seccond string, I set Black color to Background default value.