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

4

36

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>
Sinistrocular answered 24/11, 2009 at 23:14 Comment(0)
N
23

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}" />
Nad answered 25/11, 2009 at 0:26 Comment(1)
Cool, that's what I wanted to know. I added your solution to the question. Thanks!Chilblain
S
6
<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.

Shannon answered 17/11, 2013 at 2:10 Comment(1)
Great answer! Now I can specify custom background on specific controls...Knickerbockers
B
3

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.

Blades answered 24/11, 2009 at 23:29 Comment(1)
Thanks, but I am using the attached property from ancestor, so the trick with default value is not possible. As for setting it in constructor - that's writing xaml in code (which should not be necessary), and it cannot be changed by template, so I don't think this is how Microsoft's controls do it.Chilblain
W
2

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>
Warrin answered 26/3, 2012 at 12:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.