Click here to Skip to main content
Click here to Skip to main content

A Guided Tour of WPF – Part 5 (Styles)

, 13 Apr 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A guided tour of the Windows Presentation Foundation, one feature at a time.

Table of contents

  • Part 1 (XAML): Learn about XAML and how it is used in WPF applications.
  • Part 2 (Layout): Learn about layout panels and how they are used to construct user interfaces.
  • Part 3 (Data binding): Learn how WPF data binding works and how it can be used.
  • Part 4 (Data templates and triggers): Learn how data templates and triggers work and how they can be used.
  • Part 5 (Styles): Learn about how UIs can be styled in WPF.

Introduction

This is the fifth article in an introductory series about the Windows Presentation Foundation. In the previous article we examined data templates and triggers to see how the rendering of data objects can be described in XAML. In this article we examine styles, and how they are used in the WPF Horse Race demo application (which is available for download at the top of the first article in this series).

Just like the other articles in this series, this article does not cover its subject matter in exhaustive detail. Instead we will examine just enough of the basics so that we can see how those features are put to use in the demo app. If you want to learn more about how styles can be used, refer to the External links section for additional information.

Background

WPF borrows many concepts from both the Web and desktop programming worlds. The separation of user interface layout from behavior (i.e. XAML vs. code-behind) is a tip of the hat to ASP.NET. The extensive set of event-driven APIs for detailed control over user interaction is reminiscent of the Windows Forms programming model. WPF can be thought of as a distillation of the best features found in various UI platforms, plus a wide range of new features as well.

One major contribution made to WPF by the world of Web development was the concept of styles. Styling in WPF is somewhat similar to how Cascading Style Sheets (CSS) is used by Web developers. The basic idea of styling in WPF is that you can define a Style object which is applied to a specific type of element in the UI, such as a Button or TextBox. That style can be applied to every instance of the element type, or you can selectively apply it to certain instances. Styling in WPF really just boils down to a convenient way to apply property settings to one or more visual elements.

Style vs. theme

Before we start looking into styles, it is important to draw a distinction between styles and themes. Operating systems have "themes", WPF applications have "styles". Themes are an OS-level concept: such as the blue, green, and silver themes seen in Windows XP, or the Aero theme in Vista. WPF applications automatically detect the current OS theme and use that color scheme wherever possible, and can even programmatically choose which theme to use.

A style exists only within one WPF application, or just one Window in a WPF application, or even just one portion of a Window for that matter. Styles cannot be applied to anything outside of the WPF application in which they exist, nor can they be applied to any WinForms controls hosted within a WPF Window.

For more information about theme support in WPF, refer to the External links section at the end of this article.

The Style class

The entire styling infrastructure in WPF is based on the Style class. It has a relatively small set of public members, which makes it easy to grasp how styling works. Instances of the Style class are almost always created in XAML, but it is possible to create them in code if necessary.

Here are some of the properties of Style we will see in use later:

  • Resources – is a ResourceDictionary where you can put objects used only within the Style, such as brushes, value converters, etc.
  • Setters – a collection of Setter and EventSetter objects that apply values to properties, or assign handlers to events. This is the content property of the Style class, which makes it very easy to use in XAML.
  • TargetType – indicates on what type of element the Style will be applied, such as TreeView or Button.

The styles created in the WPF Horse Race demo application are very simple. There are other common properties of the Style class which they do not use, such as:

  • BasedOn – allows for style inheritance. You can derive one Style from another Style to create customizations without duplicating the core Style's XAML.
  • Triggers – just like in the DataTemplates seen in the previous article in this series, this property contains a collection of triggers that can be used to conditionally apply values to properties.

A Style can be applied to any object which derives from FrameworkElement or FrameworkContentElement, both of which expose a public property named Style.

Without styles

If WPF did not provide a way to stylize elements, you would have to be out of your mind to even consider creating a distinctive, branded look and feel for an application's user interface. To create a visual consistency across all Windows in an application would quickly turn into a maintenance nightmare, especially once changes needed to be made to certain aspects of the visual style.

For example, consider the following XAML:

<Border BorderBrush="Black" BorderThickness="2">
  <StackPanel>
    <TextBlock Background="Tan" Margin="2,4">Bike</TextBlock>
    <TextBlock Background="Tan" Margin="2,4">Car</TextBlock>
    <TextBlock Background="Tan" Margin="2,4">Truck</TextBlock>
  </StackPanel>
</Border>

That simple markup results in something which looks like this:

Suppose that the application we are building used to have a rule that TextBlocks must always have a tan background color, but one day a big wig at our imaginary company decides that tan is no longer a good color. Instead, now all TextBlocks should have a light gray background color.

If our application only had the three TextBlocks seen in the snippet above, that wouldn't be too much trouble. All we would have to do is update those three property settings:

<Border BorderBrush="Black" BorderThickness="2" Margin="10">
  <StackPanel>
    <TextBlock Background="LightGray" Margin="2,4">Bike</TextBlock>
    <TextBlock Background="LightGray" Margin="2,4">Car</TextBlock>
    <TextBlock Background="LightGray" Margin="2,4">Truck</TextBlock>
  </StackPanel>
</Border>

But if our application happens to contain hundreds or even thousands of TextBlocks, then we are in trouble. Suddenly we would be wishing that there was an easy way to set every TextBlock's Background property to light gray.

With styles

Fortunately there is an easy way to set properties on any number of elements: "styles". Let's see how a Style can be used to solve the problem described in the previous section. Here's one way to do it:

<Border BorderBrush="Black" BorderThickness="2">
  <StackPanel>
    <StackPanel.Resources>
      <Style x:Key="TxtBlkStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="Background" Value="LightGray" />
        <Setter Property="Margin" Value="2,4" />
      </Style>
    </StackPanel.Resources>
    <TextBlock Style="{StaticResource TxtBlkStyle}">Bike</TextBlock>
    <TextBlock Style="{StaticResource TxtBlkStyle}">Car</TextBlock>
    <TextBlock Style="{StaticResource TxtBlkStyle}">Truck</TextBlock>
  </StackPanel>
</Border>

The XAML seen above creates a Style in the StackPanel's Resources collection. That Style targets elements of type TextBlock, and sets their Background and Margin properties. Notice that the Style has a key, 'TxtBlkStyle'. The Style property on each TextBlock is then explicitly set to reference that Style. It results in the following UI:

It turns out that there's an even easier way to accomplish this task. If you do not give a Style a key, then it will automatically be applied to all elements whose type matches the TargetType of the Style. Here's an example:

<Border BorderBrush="Black" BorderThickness="2">
  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Background" Value="LightGray" />
        <Setter Property="Margin" Value="2,4" />
      </Style>
    </StackPanel.Resources>
    <TextBlock>Bike</TextBlock>
    <TextBlock>Car</TextBlock>
    <TextBlock>Truck</TextBlock>
  </StackPanel>
</Border>

The solutions seen so far do not really solve the overall problem. If we want the entire application to contain light gray TextBlocks, then we need to move our Style to a higher place in the resource tree, such as the Application's resources (read more about that here and here). This way, all TextBlocks in the app will be able to use the Style we created. Here is an example of this technique:

<!--<span class="code-comment"> App.xaml --></span>
<Application x:Class="WPF_Test.MyApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml"
    >
  <Application.Resources>
    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Background" Value="LightGray" />
      <Setter Property="Margin" Value="2,4" />
    </Style>
  </Application.Resources>
</Application>

<!--<span class="code-comment">Somewhere inside of SomeWindow.xaml --></span>
<Border BorderBrush="Black" BorderThickness="2">
  <StackPanel>
    <TextBlock>Bike</TextBlock>
    <TextBlock>Car</TextBlock>
    <TextBlock>Truck</TextBlock>
  </StackPanel>
</Border>

Since the Application's resource collection is the most visible place to put a Style, all TextBlocks in every Window in the app will use that Style. It is possible to override that Style in any Window or anywhere in a Window's element tree, but by default that Style will be used by all TextBlocks in the application.

How the WPF Horse Race uses styles

The WPF Horse Race demo application creates two Styles. One of them is used to affect the Border element in the data template for the RaceHorse class (as seen in the previous article in this series). The other provides common values for properties of TextBlocks in the application's "Command Strip" area, toward the bottom of the Window.

Race pit border style

If the RaceHorse data template's root Border element did not have a Style applied to it, the UI would look like this:

Screenshot - GuidedTourWPF_5_RacePit_NoStyle.png

With the Style applied, it looks like this:

Screenshot - GuidedTourWPF_5_RacePit_WithStyle.png

In the RacePitBorderStyle.xaml file, you will find a ResourceDictionary which contains a Style whose key is 'RacePitBorderStyle'. That file contains the following XAML:

<!--<span class="code-comment"> This resource dictionary contains the Style applied to
     each horse's race pit. --></span>
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Style x:Key="RacePitBorderStyle" TargetType="Border">
    <Style.Resources>
      <LinearGradientBrush x:Key="BackBrush"
        StartPoint="0.5,0" EndPoint="0.5,1"
        >
        <GradientStop Color="#88000000" Offset="0.1" />
        <GradientStop Color="#CC000000" Offset="0.9" />
      </LinearGradientBrush>
      <LinearGradientBrush x:Key="BorderBrush"
        StartPoint="0.5,0" EndPoint="0.5,1"
        >
        <GradientStop Color="#18000000" Offset="0.1" />
        <GradientStop Color="#08000000" Offset="0.9" />
      </LinearGradientBrush>
    </Style.Resources>
    <Setter Property="Background" Value="{StaticResource BackBrush}"/>
    <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="CornerRadius" Value="8" />
    <Setter Property="Margin" Value="2,4" />
  </Style>
</ResourceDictionary>

That Style is applied to the root Border element in the RaceHorse data template, as seen below:

<!--<span class="code-comment"> RaceHorseDataTemplate.xaml --></span>
<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:WpfHorseRace"
  >
  <!--<span class="code-comment"> Import the resource dictionary which contains the Style
       applied to Border of each horse's "pit". --></span>
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="RacePitBorderStyle.xaml" />
  </ResourceDictionary.MergedDictionaries>

  <DataTemplate DataType="{x:Type local:RaceHorse}">
    <Border x:Name="racePit" Style="{StaticResource RacePitBorderStyle}">
      <!--<span class="code-comment"> Other elements omitted for clarity. --></span>
    </Border>
  </DataTemplate>
</ResourceDictionary>

Command strip text style

The other Style used in the demo application is implicitly applied to its target elements. This Style can be seen in Window1.xaml, in the "Command Strip" section of the XAML.

<StackPanel Orientation="Horizontal">
  <StackPanel.Resources>
    <!--<span class="code-comment"> This Style is applied to all TextBlock
         elements in the command strip area. --></span>
    <Style TargetType="TextBlock">
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="Foreground" Value="#EE000000" />
    </Style>
  </StackPanel.Resources>
  <TextBlock>Rotation: </TextBlock>
  <Slider ... />
  <TextBlock ... />
  <TextBlock> degrees</TextBlock>
</StackPanel>

Notice that this Style's TargetType is set to "TextBlock". When the TargetType is set to a type that is part of the WPF framework, you do not have to use the more cumbersome {x:Type TypeName} syntax seen previously in this article. Since the Style seen above does not have a key, it is automatically applied to all TextBlock elements in the StackPanel.

External links

Styles and themes

Styles

Themes

History

  • April 12, 2007 - Created the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Josh Smith
Software Developer (Senior) Cynergy Systems
United States United States
Josh creates software, for iOS and Windows.
 
He works at Cynergy Systems as a Senior Experience Developer.
 
Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.
 
Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.
 
Check out his Advanced MVVM[^] book.
 
Visit his WPF blog[^] or stop by his iOS blog[^].
Follow on   Twitter

Comments and Discussions

 
AnswerGuided Tour WPF PinmemberMember 103817778-Nov-13 6:19 
GeneralMy vote of 5 PinmemberPlun20-May-13 3:49 
GeneralMy vote of 5 PinprofessionalEdo Tzumer16-May-13 4:50 
GeneralMy vote of 5 PinmemberRoland Orosz10-Dec-12 11:22 
Generalmy vote 5 PinmemberElanchezian3-Oct-12 3:54 
good article very nice, good help me
 
thank you...
GeneralMy vote of 5 PinmemberKoopakiller10-Mar-12 5:56 
GeneralMy vote of 5 PinmemberMika19923-Mar-12 4:08 
GeneralMy vote of 5 PinmemberAnil Limbani24-Feb-12 22:56 
GeneralMy vote of 5 PinmemberShlomiO8-Jan-12 22:42 
GeneralMy vote of 5 Pinmemberjtstanish16-Dec-11 7:43 
GeneralMy vote of 5 Pinmembertssutha036-Dec-11 23:21 
GeneralMy vote of 5 PinmemberT_uRRiCA_N17-May-11 23:54 
GeneralMy vote of 5 Pinmemberjiangpeipei11115-May-11 17:13 
GeneralMy vote of 5 PinmemberAhsanS26-Apr-11 20:06 
GeneralGreat Intro to WPF PinmemberFrankGallagher18-Aug-10 6:16 
GeneralRe: Great Intro to WPF PinmvpJosh Smith18-Aug-10 6:39 
GeneralVery well-written article for ultimate beginners. PinmemberTeymur Mammadov3-Aug-10 19:12 
QuestionTemplates for All Buttons? Pinmembercawoodm17-Mar-10 10:09 
QuestionRelation to MVVM Pinmemberthlorenz31-Jul-09 5:21 
GeneralStyles Themes and Tempaltes Pinmemberbradutz0129-Apr-09 23:54 
GeneralRe: Styles Themes and Tempaltes Pinmemberthlorenz5-Aug-09 12:10 
QuestionStyle RepeatButton used in Slider control Pinmembertinatran3024-Mar-09 9:09 
GeneralRe: Style RepeatButton used in Slider control Pinmembersaiwpf25-Jun-09 20:12 
GeneralStyling windows PinmemberDmitri Nesteruk6-Nov-08 10:54 
QuestionTargetType Pinmembergnurka6-Aug-08 4:07 
AnswerRe: TargetType PinmvpJosh Smith6-Aug-08 4:37 
GeneralRe: TargetType Pinmembergnurka6-Aug-08 5:07 
GeneralExcellent series PinmemberRugbyLeague23-Jul-08 6:44 
GeneralRe: Excellent series PinmvpJosh Smith24-Jul-08 10:59 
GeneralExcellent series, Josh PinmemberBert delaVega15-Apr-08 6:31 
GeneralRe: Excellent series, Josh PinmvpJosh Smith15-Apr-08 7:48 
QuestionStartup Path!!! PinmemberDonedem23-Feb-08 3:58 
GeneralRe: Startup Path!!! PinmvpJosh Smith23-Feb-08 5:56 
GeneralRe: Startup Path!!! PinmemberDonedem25-Feb-08 1:14 
QuestionRe: Startup Path!!! PinmemberDonedem3-Mar-08 3:54 
AnswerRe: Startup Path!!! PinmemberJames Wells3-Nov-08 9:42 
GeneralRe: Startup Path!!! PinmemberCory Brogden3-Mar-10 5:23 
Generalthanks for your article Pinmemberzhao8962-Sep-07 3:50 
GeneralRe: thanks for your article Pinmemberjoyjjjz23-Dec-07 22:44 
GeneralVery good walk-through the writing is straightforward PinmemberEpsilone32-Sep-07 3:12 
GeneralVery.. very.. nice! PinmemberErugJereon22-Aug-07 4:24 
GeneralRe: Very.. very.. nice! PinmvpJosh Smith22-Aug-07 4:44 
GeneralFirst time I read the series.. PinmemberPatrick Sears22-Jul-07 19:40 
GeneralRe: First time I read the series.. PinmvpJosh Smith22-Jul-07 20:15 
QuestionWizard-like page transitions PinmemberVasile Tomoiaga13-Jul-07 3:04 
AnswerRe: Wizard-like page transitions PinmemberVasile Tomoiaga15-Jul-07 22:19 
GeneralI enjoyed the journey all the way PinmemberMoim Hossain2-Jul-07 20:01 
GeneralRe: I enjoyed the journey all the way PinmvpJosh Smith2-Jul-07 20:31 
QuestionWPF Skinning Pinmembermarlongrech12-Apr-07 21:38 
AnswerRe: WPF Skinning PinmvpJosh Smith13-Apr-07 3:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 13 Apr 2007
Article Copyright 2007 by Josh Smith
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid