Overriding default control styles

When providing custom styles for our application controls, this typically requires us to define a new ControlTemplate element for each of them. As these can often be very large, it is customary to declare them in a separate resource file and merge it with the application resources in the App.xaml file, as shown in Chapter 5, Using the Right Controls for the Job.

Before starting this task, we need to plan how we want our controls to look and then apply this same look to each control. Another mistake would be to customize different controls with different styles, as consistency is key to providing a professional look. For example, if we want our single-line textboxes to be a certain height, then we should also define our other controls to be the same height.

The custom styles that we declare for our controls can be part of our application framework. If we define them without naming them via the x:Key directive, they will be implicitly applied and so, the developers that utilize our application framework need not concern themselves with the look of each control, effectively freeing them up to concentrate on aggregating them into the various Views.

The first thing to do before starting to design our custom styles is to define a small range of colors that we will use in our application. Using too many colors in an application can make it look less professional, so we should choose a few shades of a small number of colors to use. There are a number of online tools that can help us to pick a color palette to use.

Once we have chosen our application colors, we should declare them, first, as Color objects in the App.xaml file, and then declare brush elements that use them, as most controls use brushes rather than colors. This has two benefits; using only these colors will promote consistency and if we ever need to change a color, we only need to change it in a single place:

<Color x:Key="ReadOnlyColor">#FF585858</Color> 
...
<SolidColorBrush x:Key="ReadOnlyBrush" 
  Color="{StaticResource ReadOnlyColor}" /> 

It is often a good idea to also define multiple named styles for the most common types of controls. For example, having a Label style for TextBlock elements, that right aligns them and adds suitable margins, or a Heading style that sets a larger font size and heavier font weight. Providing the developers with a set of predefined styles helps to make the application look consistent.

When defining multiple named styles, it is common to reuse some of them in others. For example, if we have a default style for the TextBox control, we can base other style variations on it. Let's see some XAML examples:

<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}"> 
  <Setter Property="SnapsToDevicePixels" Value="True" /> 
  <Setter Property="Margin" Value="0,0,0,5" /> 
  <Setter Property="Padding" Value="1.5,2" /> 
  <Setter Property="MinHeight" Value="25" /> 
  <Setter Property="TextWrapping" Value="Wrap" /> 
  ... 
</Style> 
<Style x:Key="Max2LineTextBoxStyle" TargetType="{x:Type TextBox}"  
  BasedOn="{StaticResource TextBoxStyle}"> 
  <Setter Property="MaxHeight" Value="44" /> 
  <Setter Property="VerticalScrollBarVisibility" Value="Auto" /> 
  <Setter Property="ToolTip" 
    Value="{Binding Text, RelativeSource={RelativeSource Self}}" />
</Style> 
<Style x:Key="Max3LineTextBoxStyle" TargetType="{x:Type TextBox}"  
  BasedOn="{StaticResource Max2LineTextBoxStyle}"> 
  <Setter Property="MaxHeight" Value="64" /> 
</Style> 
<Style x:Key="ReadOnlyTextBoxStyle" TargetType="{x:Type TextBox}"  
  BasedOn="{StaticResource TextBoxStyle}"> 
  <Setter Property="Background" Value="{StaticResource ReadOnlyBrush}" /> 
  <Setter Property="IsReadOnly" Value="True" /> 
  <Setter Property="Cursor" Value="Arrow" /> 
</Style> 

Here, the simplified TextBoxStyle style defines the majority of the properties for all TextBox controls. The Max2LineTextBoxStyle style inherits all of the property settings from this style and sets a few more that ensure that the vertical scrollbar can appear when required and enforce a maximum height for the control.

The Max3LineTextBoxStyle style extends the Max2LineTextBoxStyle style and so, inherits all of its property settings, as well as those of the TextBoxStyle style. It overrides the MaxHeight property that was set in the previous style. The ReadOnlyTextBoxStyle style also extends the TextBoxStyle style and sets properties to ensure that the control is read-only. Defining styles in this way ensures that controls in each View will remain consistent.

As well as defining default styles for our application controls, it is often also a good idea to provide default data template resources for each data Model in the application. In a similar way to the controls, predefining these data templates can result in improved consistency. We can also define a number of named templates to override the default ones with and use in different scenarios.

If there are a large number of data models in an application, it can be helpful to also declare their data templates in a separate resource file and merge it with the application resources in the App.xaml file, like to the default control templates. It is therefore not unusual to see multiple resource files being merged in the application resources file.