Styles, Resources, and Control Templates in WPF

Published: 05 Nov 2007
By: Brian Mains
Download Sample Code

This article will show how to use Styles, Resources, and Control Templates in WPF.

Resources

Resources store reference to an object within a collection. For instance, most objects in the WPF framework have a Resources collection. The Application object, Window, Button, and other WPF controls all have a Resources collection. A resource can be anything, such as a Brush to use for painting the background, a control template (which we'll look at later), or many other types of objects. Below is an example of a brush defined in the windows resource collection.

In the previous example, the Window defines a gradient brush with a key of BlueButtonBackground. The background can be referenced using the BlueButtonBackground key like so:

StaticResource is an extension that is used to reference items defined in a resource collection. If not found in the immediate element's resource collection (the button's), it navigates up the stack until it can find the resource with that key. If the button resides in a StackPanel control - which resides in a Grid - the resource will be sought for in the button first, StackPanel second, Grid third, Window fourth, and so on. Resources can contain anything, and the last section on Control Templates will illustrate how the control template itself will be defined and referenced as a resource.

Resources can also be stored in a central place, such as a resource dictionary. A resource dictionary is a collection of resources that can be easily incorporated into an application. They can be used to contain a single reference to all the assemblies in a single or multiple applications. The following is a simple resource dictionary.

To include a resource dictionary in a Window or user control, include the following definition:

The referenced resource dictionary is now included in the user control, and any resources are automatically applied.

Styles

With ASP.NET 2.0 came a feature called themes. Themes had the ability to set styles to the inner style properties of a control. Any property that defined a ThemeableAttribute with a constructor value of true could assign that property in the skin file, using the same markup as the control (for the most part). Styles do not have the same markup as themes do, but the approach is the same.

A style can set the inner properties of a XAML element using setters, as will be illustrated soon. We can define event triggers, which are styles that are applied when an event occurs. An even more useful approach is to use a style trigger, which applies itself whenever a target condition is evaluated to true. For instance, it is possible to change the background color and foreground color whenever a button is pressed, and then revert back to the original setting when that event is false. This works because of the change notification that elements provide when the value exposed by a property changes.

An example style is shown below:

This style is defined in the Window's Resources collection. The style is given a key, so it can be uniquely referenced. A series of setters can be defined in order to specify which properties will be changed. In the example above, only two setters are defined, but you could have continued on with many more entries. In the following example, the style changes the background property to a gradient brush. To use this style, the following code defines a static resource extension and embeds it in a control's background:

In this situation, a style is applied to a button. But it doesn't have to be; it could be applied to many types of elements. Suppose that the only target for this style was a button; using a different property, we can apply it to only buttons:

In this situation, the style is applied to all buttons, depending on where it is defined (if in the application, Window, resource dictionary, or local resource collection). TargetType looks for any instance of a button and applies the appropriate style. With this approach, the Control prefix on the setter property is no longer needed.

Triggers can be used for styles as well. For instance, a button has several properties it can use to determine what state it is in. It has an IsPressed property that is used to determine whether a mouse button is currently pressed, an IsEnabled property that determines if the button is enabled, an IsFocused property for determining whether the control has focus (such as when tabbing through the controls on a form), and many more. Each of these properties can be used in a style trigger to perform some action. Take the definition below:

Upon pressing the button, the background changes from a lighter gradient to a darker one. This happens because the control has its own change notification. When the button is pressed, the "swap is made". Triggers require that the comparison is an equality comparison. A trigger can't be used to determine if a property is within a specific range. Rather, it often checks if a value matches its condition exactly.

Styles also have the ability to inherit from each other, by specifying the key of another style in the BasedOn attribute. The following is a style that inherits from another style. All of the base styles are applied, and additional ones are defined in the new style shown below.

As you can see, style inheritance is easy to do.

Control Templates

Each control has a base template that it uses to render its user interface. This interface is a template and is instantiated whenever the control is displayed. The control itself is made up of a lot of different parts; but often includes styles and style triggers, and utilizes resources in several ways.

A control template is actually an element that one can define in a resources collection, or in a resource dictionary. The following declaration is perfectly valid:

To use this template, a button must be declared as follows:

Using this approach, the following template can add a rounded corner border to a button control. In addition, the button has an inner white square border, and includes a commonly-used text statement at the top.

Our button has a rounded corner border consisting of blue colors. Note the ContentPresenter declaration; this declaration allows the inner content of the button to be bound inside the control. So the text "Templated Button" is rendered inside the templated button.

Styles can be used to apply a control template. For example, it is possible to apply a style template using the following style (note that the style is still set the same way, by applying it through the Style property).

In addition, a template can be applied automatically, simply by using the TargetType attribute on a style. The following applies the control template to all buttons:

A button can ignore this style by manually applying a style with the {x:Null} property value.

Summary

Resources and styles are great ways to modify the basic appearance of a .NET application. Control templates still rely on these capabilities to provide a stellar user interface. Resources provide an excellent way to define certain objects in a global location, and resource dictionaries provide a way to make resources available at a global scale. Styles are really dynamic in their ability to set property values, because they can listen to property changes and apply certain values through a trigger; only when the trigger condition is met.

I discussed control templates from the perspective of styles and resources. However, control templates have the ability to customize the user interface. Although there are some precautions to take, control templates have the powerful ability to completely redesign the user interface.

In the examples provided, the styles, resources, and control templates are mostly embedded in the main Window. However, it would be a better approach to split them into a more centralized place, like a resource dictionary.

About Brian Mains

Brian Mains is an application developer consultant with Computer Aid Inc. He formerly worked with the Department of Public Welfare. In both places of business, he developed both windows and web applications, small and large, using the latest .NET technologies. In addition, he had spent many hou...

View complete profile

Top Articles in this category

Introduction to WPF Animations
WPF is a new framework that has many advanced capabilities. Animations are one of those capabilities, where an object can be animated via rotating, stretching, scaling, moving it across the screen, changing its color, etc. This article will show some of the basic animations.

WPF Data Binding, With LINQ
Brian Mains explains how to perform data binding in WPF with LINQ.

Soup to Nuts: WPF Enterprise Example with “Rails” Style UI
This article demonstrates some best practices for developing WPF applications. A complete “enterprise” ready architecture is recommended covering everything from data access to presentation. Of particular interest is an MVP UI framework inspired by “Rails” which is included with the downloadable solution.

More WPF Animations
WPF (Windows Presentation Foundation) has many ways to manipulate objects. Some of these ways involve transforming an object, or using animation to animate the various values of an object. These can all work together to provide a very interactive interface. This article will show you how.

WPF Flow Documents and Images
Brian mains shows how to use the flow documents and images.

Top
 
 
 

Please login to rate or to leave a comment.

Product Spotlight