MCTS Self-Paced Training: Styles and Animation in Windows Presentation Foundation

  • 7/9/2008

Using Styles

Styles can be thought of as analogous to cascading style sheets as used in Hypertext Markup Language (HTML) pages. Styles basically tell the presentation layer to substitute a new visual appearance for the standard one. They allow you to make changes to the user interface as a whole easily and to provide a consistent look and feel for your application in a variety of situations. Styles enable you to set properties and hook up events on UI elements through the application of those styles. Further, you can create visual elements that respond dynamically to property changes through the application of triggers, which listen for a property change and then apply style changes in response.

Properties of Styles

The primary class in the application of styles is, unsurprisingly, the Style class. The Style class contains information about styling a group of properties. A Style can be created to apply to a single instance of an element, to all instances of an element type, or across multiple types. The important properties of the Style class are shown in Table 7-1.

Table 7-1 Important Properties of the Style Class

Property

Description

BasedOn

Indicates another style that this style is based on. This property is useful for creating inherited styles.

Resources

Contains a collection of local resources used by the style. The Resources property is discussed in detail in Chapter 9, “Resources, Documents, and Localization.”

Setters

Contains a collection of Setter or EventSetter objects. These are used to set properties or events on an element as part of a style.

TargetType

This property identifies the intended element type for the style.

Triggers

Contains a collection of Trigger objects and related objects that allow you to designate a change in the user interface in response to changes in properties.

The basic skeleton of a <Style> element in XAML markup looks like the following:

<Style>
   <!-- A collection of setters is enumerated here -->
   <Style.Triggers>
   <!-- A collection of Trigger and related objects is enumerated here -->
   </Style.Triggers>
   <Style.Resources>
      <!-- A collection of local resources for use in the style -->
   </Style.Resources>
</Style>

Setters

The most common class you will use in the construction of Styles is the Setter. As their name implies, Setters are responsible for setting some aspect of an element. Setters come in two flavors: property setters (or just Setters, as they are called in markup), which set values for properties; and event setters, which set handlers for events.

Property Setters

Property setters, represented by the <Setter> tag in XAML, allow you to set properties of elements to specific values. A property setter has two important properties: the Property property, which designates the property that is to be set by the Setter, and the Value property, which indicates the value to which the property is to be set. The following example demonstrates a Setter that sets the Background property of a Button element to Red:

<Setter Property="Button.Background" Value="Red" />

The value for the Property property must take the form of the following:

Element.PropertyName

If you want to create a style that sets a property on multiple different types of elements, you could set the style on a common class that the elements inherit, as shown here:

<Style>
   <Setter Property="Control.Background" Value="Red" />
</Style>

This style sets the Background property of all elements that inherit from the Control to which it is applied.

Event Setters

Event setters (represented by the <EventSetter> tag) are similar to property setters, but they set event handlers rather than property values. The two important properties for an EventSetter are the Event property, which specifies the event for which the handler is being set; and the Handler property, which specifies the event handler to attach to that event. An example is shown here:

<EventSetter Event="Button.MouseEnter" Handler="Button_MouseEnter" />

The value of the Handler property must specify an extant event handler with the correct signature for the type of event with which it is connected. Similar to property setters, the format for the Event property is

Element.EventName

where the element type is specified, followed by the event name.

Creating a Style

You’ve seen the simplest possible implementation of a style: a single Setter between two Style tags, but you haven’t yet seen how to apply a style to an element. There are several ways to apply a style to an element or elements. This section examines the various ways to apply a style to elements in your user interface.

Setting the Style Property Directly

The most straightforward way to apply a style to an element is to set the Style property directly in XAML. The following example demonstrates directly setting the Style property of a Button element:

<Button Height="25" Name="Button1" Width="100">
   <Button.Style>
     <Style>
        <Setter Property="Button.Content" Value="Style set directly" />
        <Setter Property="Button.Background" Value="Red" />
     </Style>
   </Button.Style>
</Button>

While setting the Style directly in an element might be the most straightforward, it is seldom the best method. When setting the Style directly, you must set it for each element that you want to be affected by the Style. In most cases, it is simpler to set the properties of the element directly at design time.

One scenario where you might want to set the Style directly on an element is to provide a set of Triggers for that element. Because Triggers must be set in a Style (except for EventTriggers, as you will see in the next section), you conceivably could set the Style directly to set triggers for an element.

Setting a Style in a Resources Collection

The most common method for setting styles is to create the style as a member of a Resources collection and then apply the style to elements in your user interface by referencing the resource. The following example demonstrates creating a style as part of the Windows.Resources collection:

<Window.Resources>
   <Style x:Key="StyleOne">
      <Setter Property="Button.Content" Value="Style defined in resources" />
      <Setter Property="Button.Background" Value="Red" />
   </Style>
</Window.Resources>

Under most circumstances, you must supply a key value for a Style that you define in the Resources collection. Then you can apply that style to an element by referencing the resource, as shown in bold here:

<Button Name="Button1" Style="{StaticResource StyleOne}" Height="30"
   Width="200" />

The advantage to defining a Style in the Resources section is that you can then apply that Style to multiple elements by simply referencing the resource. Resources are discussed in detail in Chapter 9.

Applying Styles to All Controls of a Specific Type

You can use the TargetType property to specify a type of element to be associated with the style. When you set the TargetType property on a Style, that Style is applied to all elements of that type automatically. Further, you do not need to specify the qualifying type name in the Property property of any Setters that you use—you can just refer to the property name. When you specify the TargetType for a Style that you have defined in a Resources collection, you do not need to provide a key value for that style. The following example demonstrates the use of the TargetType property:

<Window.Resources>
   <Style TargetType="Button">
      <Setter Property=" Content" Value="Style set for all buttons" />
      <Setter Property="Background" Value="Red" />
   </Style>
</Window.Resources>

When you apply the TargetType property, you do not need to add any additional markup to the elements of that type to apply the style.

If you want an individual element to opt out of the style, you can set the style on that element explicitly, as seen here:

<Button Style="{x:Null}" Margin="10">No Style</Button>

This example explicitly sets the Style to Null, which causes the Button to revert to its default look. You also can set the Style to another Style directly, as seen earlier in this lesson.

Setting a Style Programmatically

You can create and define a style programmatically. While defining styles in XAML is usually the best choice, creating a style programmatically might be useful when you want to create and apply a new style dynamically, possibly based on user preferences. The typical method for creating a style programmatically is to create the Style object in code; then create Setters (and Triggers, if appropriate); add them to the appropriate collection on the Style object; and then when finished, set the Style property on the target elements. The following example demonstrates creating and applying a simple style in code:

' VB
Dim aStyle As New Style
Dim aSetter As New Setter
aSetter.Property = Button.BackgroundProperty
aSetter.Value = Brushes.Red
aStyle.Setters.Add(aSetter)
Dim bSetter As New Setter
bSetter.Property = Button.ContentProperty
bSetter.Value = "Style set programmatically"
aStyle.Setters.Add(bSetter)
Button1.Style = aStyle

// C#
Style aStyle = new Style();
Setter aSetter = new Setter();
aSetter.Property = Button.BackgroundProperty;
aSetter.Value = Brushes.Red;
aStyle.Setters.Add(aSetter);
Setter bSetter = new Setter();
bSetter.Property = Button.ContentProperty;
bSetter.Value = "Style set programmatically";
aStyle.Setters.Add(bSetter);
Button1.Style = aStyle;

You can also define a style in a Resources collection and apply that style in code, as shown here:

<!-- XAML -->
<Window.Resources>
   <Style x:Key="StyleOne">
      <Setter Property="Button.Content" Value="Style applied in code" />
      <Setter Property="Button.Background" Value="Red" />
   </Style>
</Window.Resources>

' VB
Dim aStyle As Style
aStyle = CType(Me.Resources("StyleOne"), Style)
Button1.Style = aStyle

// C#
Style aStyle;
aStyle = (Style)this.Resources["StyleOne"];
Button1.Style = aStyle;

Implementing Style Inheritance

You can use inheritance to create styles that conform to the basic look and feel of the original style but provide differences that offset some controls from others. For example, you might create one Style for all the Button elements in your user interface and create an inherited style to provide emphasis for one of the buttons. You can use the BasedOn property to create Style objects that inherit from other Style objects. The BasedOn property references another style and automatically inherits all the members of that Style and then allows you to build on that Style by adding additional members. The following example demonstrates two Style objects—an original Style and a Style that inherits it:

<Window.Resources>
   <Style x:Key="StyleOne">
      <Setter Property="Button.Content" Value="Style set in original Style" />
      <Setter Property="Button.Background" Value="Red" />
      <Setter Property="Button.FontSize" Value="15" />
      <Setter Property="Button.FontFamily" Value="Arial" />
   </Style>
   <Style x:Key="StyleTwo" BasedOn="{StaticResource StyleOne}">
      <Setter Property="Button.Content" Value="Style set by inherited style" />
      <Setter Property="Button.Background" Value="AliceBlue" />
      <Setter Property="Button.FontStyle" Value="Italic" />
   </Style>
</Window.Resources>

The result of applying these two styles is seen in Figure 7-1.

Figure 7-1

Figure 7-1 Two buttons—the original and an inherited style

When a property is set in both the original style and the inherited style, the property value set by the inherited style always takes precedence. But when a property is set by the original style and not set by the inherited style, the original property setting is retained.