views:

622

answers:

2

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>
A: 

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.

Aran Mulholland
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.
Tomáš Kafka
+1  A: 

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}" />
Michael Morton
Cool, that's what I wanted to know. I added your solution to the question. Thanks!
Tomáš Kafka