Chapter 9. Styling Your Application

One of the key features of XAML is that it enables exceptional user interfaces to be designed and implemented in Silverlight. When designing the look and feel of your application however, you don't want to have to customize each control and user interface element individually. This is where the use of style resources comes in—they enable you to maintain a core set of common styles to be used throughout your application.

Expression Blend has been designed to help you in the styling process, but in this chapter, we'll focus on the core fundamentals of styling in Silverlight, particularly how the styling model is structured and works, so that you can then take advantage of it however you wish. This chapter won't discuss how to make your application more attractive, but it will take you through the various aspects of controlling the appearance of controls through XAML and maintaining these as reusable resources.

The Designer/Developer Workflow

The ability for XAML–based controls to be extensively styled and templated enables you to radically customize their appearance and permits the creation of visually pleasing applications. User interfaces can be designed that engage users and draw them into using the application. However, simply using the Silverlight controls out of the box, on the default white canvas, can lead to a rather plain application, often followed by badly implemented attempts to make it more interesting by developers who may not have the skills to do so effectively. Unfortunately, this process results in many unsightly user interfaces. Silverlight projects can, therefore, greatly benefit from having a designer on board to create an attractive user interface.

Including designers as a part of the development process has therefore been a focus for Microsoft. That said, Visual Studio is not an application suited for use by designers, so Microsoft created the Expression Suite targeted toward the needs of designers. From the Expression Suite, the Expression Blend and Expression Design tools are those that will be most useful to graphic designers when working on Silverlight projects.

Expression Blend is targeted toward designing XAML–based user interfaces for Silverlight and WPF. This includes extensive support for laying out controls, styling and templating them, and creating and applying animations to elements of the user interface. With Visual Studio 2010's new Silverlight designer, we now have support for a drag-and-drop design surface that we can view and interact with at design time (a feature not available in Visual Studio 2008 - with hand-coding XAML being the only option). Therefore, developers who worked with XAML in addition to code now have less reliance on Expression Blend than they may have previously. That said, however, Expression Blend still offers many design-related features that Visual Studio does not (without modifying the XAML directly, which can often be complex and inefficient); these include

  • Designing and applying animations (including transition animations) to user interface elements. Animations can involve a lot of XAML, which would have to be hard-coded in Visual Studio. Not only does Expression Blend provide a friendly user interface for creating animations but it also allows you preview the animation at design time without needing to compile and run your application first.

  • Control templating (discussed later in this chapter) is vastly easier in Expression Blend (it is a very manual and convoluted task in Visual Studio), as is creating control templates for your own custom controls (discussed in Chapter 11, "Creating Custom Controls").

  • Expression Blend enables you to populate your user interface with sample data at design time, allowing you to preview how the interface will look when running and customize your design accordingly.

These are just some of the areas in which Expression Blend provides guidance and makes those tasks much easier to implement. Therefore, for any nontrivial user interface design, it's generally recommended (but not essential) that you include Expression Blend as one of your tools.

Just as Visual Studio 2010 has some design-related features, Expression Blend also has some code-related features too. Expression Blend can compile and run projects, and you can also modify code. However, Expression Blend's code-related features are as minimal as Visual Studio's design features. There are just enough code-related features in Expression Blend to do basic tasks, but not enough for someone to solely use Expression Blend to create a Silverlight application in an efficient manner.

Microsoft has designed the Visual Studio and Expression Blend tools to enable developers and designers to work alongside each other on the same project in harmony. The two complement each other. Designers can work on the visual aspects of the application, while developers work on the code aspects simultaneously. This approach can be even more effective when using the Model-View-ViewModel (MVVM) design pattern discussed in Chapter 12, as it promotes a clear separation of the presentation of a view and its corresponding logic. This separation makes it much easier to enable both a designer and a developer to work on the same part of the project at the same time, with reduced numbers of collisions between them.

Expression Design is another tool for graphics designers focused toward working with vector graphics. Expression Blend has some support for working with vector graphics, but Expression Design is more targeted in that direction (with Expression Blend targeted toward designing user interfaces). Therefore, you could break up the graphics designer role further to a user interface designer (who would use Expression Blend) and a graphics designer (who would use Expression Design). However, these roles often blend into a single graphics designer role in practice.

Another role that is starting to become more popular in software projects is the user experience designer. A user experience designer typically takes the functional requirements of what the software is to do and creates a design for how the user will interact with the software that implements those requirements in the most efficient and user-friendly manner.

User experience design faces a lot of misconceptions, and many people confuse it with the role of making the application attractive, believing that designing how users interact with the application is the role of the graphics designer. However, these should be treated as two completely separate skill sets: a user experience designer will determine the flow of the application based on the functional requirements, whereas a graphics designer will take this flow and implement it as an attractive user interface.

Another common misconception is that the graphic design or styling of the application should be one of the first tasks undertaken in the project. In fact, user experience design should be the main focus early on, with the styling performed later in the project. Support for the eventual styling should, of course, be included as a part of the user interface development process, but the interaction aspects are far more important to do up front. For this purpose, Microsoft added SketchFlow to Expression Blend. User experience designers can use SketchFlow to map the flow and rough layout of the application in order to generate prototypes

As a summary, Visual Studio is targeted at developers, Expression Blend and Expression Design are targeted at user interface and graphics designers, and SketchFlow is targeted toward user experience designers.

Since this book is primarily targeted for developers, we are focusing primarily on what can be done in Visual Studio. Therefore, aspects such as how to use the Expression tools and how to create animations (which really requires Expression Blend to implement efficiently) will not be covered here.

Note

In theory, the developer, graphics designer, and user experience designer should all be different people with dedicated roles and skill sets. However, in reality, this is not always the case. If your developer role includes design, you may need to become familiar with more than one of these products and switch between them, but promoting a clear separation between these roles generally leads to better software.

Defining Style Resources

The simplest form of styling your user interface is to assign values to properties exposed by controls (using attribute syntax). However, this will very soon lead to your XAML becoming an unmaintainable mess, with your XAML files increasing in complexity and becoming unwieldy and hard to read, and any necessary styling changes will often need to be made in numerous places within the application—essentially, you will have spaghetti XAML code.

The answer to this problem is to use style resources. Defining and using style resources has numerous advantages. If we want to change the styling of all our TextBox controls, we only need to set the value in one place, and it will automatically be applied to all the controls that reference that style. This simplifies the XAML by removing the need to apply the same property values on each element repeatedly. It also creates a clearer separation between your control definitions and their appearance.

You could consider style resources to be similar to CSS styles in traditional HTML–based web development. With CSS, you can define a style specifying various property values in your CSS file (or in your HTML page header) and apply that style to HTML elements by assigning the name of the style to their class property. Alternatively, you can define a style that specifies the values that the properties on all controls of a given type should automatically use. You can then override the property values defined in these styles by assigning different property values on the control definitions themselves.

Styling in Silverlight works in a similar fashion. Style resources can be defined in a resource dictionary (or within a XAML file itself) and applied to controls by assigning the style's key to their Style property. Or you can exclude the key from a style resource definition, and all the controls of the given type will automatically use that style (a feature known as implicit styling, new in Silverlight 4). Note, however, that unlike CSS, the style resource is specific to the given control type, meaning you cannot create a style that defines a set of property values to be used by both TextBox controls and ComboBox controls for example.

In Chapter 3, "An Introduction to XAML," we have already discussed the concept of style resources, demonstrating how you could define commonly assigned property values on a control as a style resource and then apply that to the Style property of any controls that use it. However, we will start with a quick overview and move on to discuss some more advanced styling features.

Defining a Style Resource

There are two ways of defining style resources: as explicit and implicit styles. Let's take a look at each of these in turn.

Explicit Styles

Let's say we have multiple TextBox controls in our project that will use the same common property values. Instead of assigning the same property values to each control, like this

<TextBox Name="FirstNameField" Margin="2" Background="LemonChiffon" Grid.Row="0" />
<TextBox Name="LastNameField" Margin="2" Background="LemonChiffon" Grid.Row="1" />
<TextBox Name="CompanyField" Margin="2" Background="LemonChiffon" Grid.Row="2" />

We can, instead, define these properties as a style resource:

<Style x:Key="UserFieldsStyle" TargetType="TextBox">
    <Setter Property="Margin" Value="2" />
    <Setter Property="Background" Value="LemonChiffon" />
</Style>

When defining our style resource, we are giving it a unique key to reference it by (using the x:Key attached property from the XAML namespace) and specifying the type of control it can be applied to (using the TargetType property). After that, it's a case of creating a Setter element for each property you want to define a value for and providing it the name of the property and its corresponding value. Now, we can reference the style with the Style property on our controls, using the StaticResource XAML markup extension that points toward the style resource (using the key of the style resource as the reference).

<TextBox Name="FirstNameField" Grid.Row="0"
         Style="{StaticResource UserFieldsStyle}" />
<TextBox Name="LastNameField" Grid.Row="1"
         Style="{StaticResource UserFieldsStyle}" />
<TextBox Name="CompanyField" Grid.Row="2"
         Style="{StaticResource UserFieldsStyle}" />

Note

You can override the values from the style resource by simply applying alternate property values directly to the control itself (i.e., via inline styles).

This is a process of explicitly assigning a style to a control. We gave the style resource a key and explicitly assigned that style to a control.

Implicit Styles

Alternatively, you may want to implicitly assign a style resource to all controls within a given scope. This is now possible in Silverlight 4 using the new implicit styles functionality. Simply omit the key when defining a style resource, and all controls of the given type within the scope of that resource will automatically use that style. For example, if you define the previous style resource (without a key defined) at a view level (e.g., in Page.Resources or UserControl.Resources), all the TextBox controls within that view will automatically use that style. If the style resources are defined at the application level, they will used by controls application-wide (a typical scenario when creating themes, discussed later in this chapter).

Complex values can also be stored in styles. For example, defining a gradient background as a style requires you to use property element syntax when defining the value of the Background property, much as you would do if assigning the gradient directly on the control itself:

<Style x:Key="UserFieldsStyle" TargetType="Control">
    <Setter Property="Margin" Value="2" />
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                <GradientStop Color="LemonChiffon" Offset="0" />
                <GradientStop Color="#FFFFFFCD" Offset="1" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

Note

Microsoft recommends that you avoid assigning values to properties in style resources where the property is defining behavior (as opposed to appearance).

Defining Style Resources at Various Locations

Style resources can be defined at various levels of the object hierarchy, and the level at which a style defined provides its scope. Let's look at the most common locations for defining style resources in your project.

At the View Level

If style resources are defined at the view level (i.e., in Page.Resources or UserControl.Resources in a XAML file), they will be available to be used by all the controls in that view only, whereas styles defining at the application level can be used by any view in that project.

Note

In addition, you could specify a style resource in the Resources property of any element in the control hierarchy, enabling it to be used (only) by the descendents of that element, although this isn't recommended due to potential maintainability issues (specifically because of confusion as to where a style resource definition can be found).

At the Application Level

To define application-wide style resources, the resources will need to be defined in the Application.Resources property of the App.xaml file.

As a Resource Dictionary

Style resources defined at the application level are often defined in a resource dictionary and merged into the application's resources. This strategy has the following benefits:

  • Keeps the style resource definitions from clogging up the App.xaml file

  • Enables the style resources to be reused among projects

  • Enables different style resources dictionaries to be easily swapped in and out

  • Enables your application to be themed (discussed later in this chapter)

The best example of this strategy is already implemented in the project you've generated from the Silverlight Business Application project template. All style resources are defined in a resource dictionary called Styles.xaml (found in the Assets folder). This file is then merged into our application resources (in the App.xaml file) like so:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Assets/Styles.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Note

Multiple resource dictionaries can be merged into a single Resources property. Therefore, you can maintain a logical separation between your style resources, avoiding resource dictionaries becoming too large and complex, and enabling multiple users to define styles at the same time. If a style is defined in more than one resource dictionary, the last one to be merged will used. If you have two implicit styles targeting the same control, the property setters won't be merged into a single style, but only the last style will be used.

Alternatively, if you have only a single resource dictionary to merge, you can simply assign the resource dictionary to the Application.Resources:

<Application.Resources>
    <ResourceDictionary Source="Assets/Styles.xaml" />
</Application.Resources>

You can create a new resource dictionary by adding a new item to your project and selecting the Silverlight Resource Dictionary project template. This will leave you with an empty resource dictionary structure to which you can add your style definitions. For example, here is the UserFieldsStyle style resource we created earlier defined in a resource dictionary:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style x:Key="UserFieldsStyle" TargetType="TextBox">
        <Setter Property="Margin" Value="2" />
        <Setter Property="Background" Value="LemonChiffon" />
    </Style>
</ResourceDictionary>

As a Resource Dictionary in a Referenced Assembly

Themes are often defined in a resource dictionary, and it can be useful to have this resource dictionary in its own assembly so that you can maintain the theme in a single location and use it in multiple projects.

Add a reference to this assembly in your project. You can then merge the resource dictionary into your application's resources as previously demonstrated. However, the path to the view needs to be of the form "/[assembly];component/[viewpath]". For example, if the ThemeStyles.xaml view existed in a referenced assembly named MyTheme.dll, the path to navigate to it would be "/MyTheme;component/ThemeStyles.xaml".

<Application.Resources>
    <ResourceDictionary Source="/MyTheme;component/ThemeStyles.xaml" />
</Application.Resources>

In Generic.xaml

Custom controls generally have their styles and control templates defined in a resource dictionary named Generic.xaml (which does not need to be merged into any Resource property but must be placed under the Themes folder in the project where the corresponding controls are defined). This will be discussed in Chapter 11, "Creating Custom Controls."

Naming Style Resources

As a part of our design process, we need to look further than just how each control type will be styled, and design and name styles based on their purpose within the application rather than what they consist of or the type of control they will be applied to. For example, you might have a TextBlock style resource that you want to use throughout your application to make the text bold, with a font size of 12 points, and colored navy. How should you name this style resource? Maybe TextBlockStyle, or BoldNavy12ptStyle, or PageHeaderStyle / PageHeaderTextBlockStyle?

From both a management and a visual design perspective, PageHeaderStyle or PageHeaderTextBlockStyle would be best way to name the style resource, because this name makes it easy to see what the purpose of each style is when navigating the style resource definitions. Also, if you are designing a new theme for the application (or plan to support multiple themes), it makes much more sense, as you are linking each style to a purpose rather than linking each style to how it is rendered on screen.

So even if two different definitions of a style resource have exactly the same property values (for example, both 12pt Bold Navy), it is generally still better to define them as separate style resources. This may result in multiple styles containing the same property values but provides better support for future restyling.

Inheriting Style Resources

Only a single style resource can be applied to a control, which may initially seem somewhat limiting when you are designing your style resources. For example, you may wish to define some property values in a base style resource common to most or all controls of a given type, and then you might want to define another style resource with additional property values to be applied to only some controls of that type (without having to define the same property values again on the new style resource that were defined on the base style resource).

While you may not be able to apply both those style resources to a control, you can have your new style resource inherit the property value definitions from the base style resource, which will serve the same purpose. This is achieved via the BasedOn property on the Style object, to which you can assign a reference to another style resource to act as the base style. This will need to be as a resource, hence the need for the StaticResource markup extension. For example, say we have this base style resource:

<Style x:Key="UserFieldsStyleBase" TargetType="TextBox">
    <Setter Property="Margin" Value="2" />
    <Setter Property="Background" Value="LemonChiffon" />
</Style>

When defining a new style resource that should be based on this one, we can reference it using the BasedOn property, like so:

<Style x:Key="UserFieldsStyle" TargetType="TextBox"
       BasedOn="{StaticResource UserFieldsStyleBase}">
    <Setter Property="TextAlignment" Value="Right" />
</Style>

Note

A style resource can only be based on a single style, but that style can be based upon another style, and so on.

Not only can you inherit the property value definitions from a base style resource using this method but you can also override some of those property value definitions. For example, despite the Background property having a value of LemonChiffon in the base style resource, we are overriding that value in this style resource to assign a value of White instead:

<Style x:Key="UserFieldsStyle" TargetType="TextBox"
       BasedOn="{StaticResource UserFieldsStyleBase}">
    <Setter Property="Background" Value="White" />
</Style>

If you have a style resource that inherits a property value, but you want to use the default value in this resource instead, you can simply null its value like so:

<Setter Property="Background" Value="{x:Null}" />

Note

The target control type from which you inherit a style resource must match that of the new style resource. For example, you cannot have a style resource targeting the TextBox control inherit from one targeting the ComboBox control. You can, however, have a style resource that inherits from one targeting one of its base classes. For example, a style resource targeting the TextBox control can inherit from a style resource targeting the Control class.

Styling Constraints

There are a few issues that you should be aware of when defining style resources:

  • Only a single style resource can be assigned to a control, and any further property values that need to be applied must be done inline on the control definition itself.

  • Style resources cannot be applied to controls of different types. Each style resource has a single control type that it applies to, meaning that you cannot have a TextBox and a ComboBox control reference the same style resource. You can assign the target type to be a class common to both those controls (such as Control), but you will often find that the properties you wish to define values for will not exist on that base class, and therefore, the project will not compile. Note that attempting this with implicit style resources will not work. The type of controls that will automatically use implicit styles must match the given target type of the style resource; otherwise, the style will not be applied.

  • Once you have assigned a style resource to a control, any implicit style that the control may have otherwise used will no longer be used by this control.

Control Templates

You have now seen how we can define a style resource and apply it to controls, but what if we completely want to change the appearance of the control, including the appearance or function of elements not exposed by the control as properties? In Silverlight, this is actually possible by applying an alternate control template to the default one defined by the control. The structure of Silverlight custom controls encourages a separation between presentation and behavior. The behavior of the control should be defined in the code, and its appearance should be defined in the control template. Between the two is a contract defining what the code needs access to from the presentation layer. With this clear separation of concerns, you can completely modify the appearance of a control without affecting its behavior, as long as you adhere to the control's behavior/presentation contract. This is an extremely powerful feature of XAML and really demonstrates its flexibility when defining user interfaces.

Note

A style enables you to simply assign property values to a control, while a control template enables you to directly modify the core XAML of the control itself.

Default Control Templates

Default control templates (and styles) are defined in the Generic.xaml file in the Themes folder of the project or assembly containing the control. Each control template has its own resource dictionary within this file. When you want to apply your own alternate custom control template to a control, the easiest way to start is by making a copy of the default control template of that control and working from there. The easiest way to extract the default control template is using Expression Blend. It will extract the control template for that control from the Generic.xaml file in the control's assembly and place it (based on your selection) in the resources of the user control or the application as a new resource. You can then change this control template resource as you see fit—move elements around, add additional control elements, remove elements, and restyle elements—as long as you keep the template parts and states referenced by the control itself.

Unfortunately, without using Expression Blend, the only way to get the existing control template is to follow these steps:

  1. Open the Generic.xaml file of the assembly that contains the control you want to modify. If you don't have the source code for the control, you will need to open the assembly using Reflector and extract the Generic.xaml file from there.

  2. Find the style resource / control template pertaining to the control, and copy it into your project as a new style resource / control template.

  3. Assign that new style resource / control template to your control.

As you can see, this is a somewhat messy and convoluted process, but Expression Blend helps to simplify and streamline this process.

Templating a Control

To make a copy of a control's default template using Expression Blend (so that you can edit it), right-click the control (in design view), and select Edit Control Parts (Template)

Templating a Control

Note that despite the name of the function, this process actually creates a style resource for the control, not a control template resource (though the style resource contains the control template), and this style resource will be referenced by the Style property on the control (a style can set property values, and Template is a property on the control). If you already have a style assigned to this control, a control template resource would be created instead and assigned to the control's Template property (as you might have otherwise expected as per the name of the function).

You will find that creating a control template resource inserts a lot of XAML markup into your XAML file (the amount will depend on the complexity of the control, and some controls like the DataGrid can be very complex). There is no way to minimize the amount of XAML generated without simplifying the visual structure of the control itself. For example, if you only wanted to make a slight adjustment to an existing element in the template, it's an all-or-nothing approach. Before customizing a control template, though, it is worth ensuring there isn't a style or template property on the control that will allow you to style or customize just a part of the control without resorting to customizing the entire template.

For the sake of completion, you don't actually have to create styles and control templates as resources (though it makes little sense not to, because if the style or template is a resource, you can easily apply it to other controls within the same scope). They can also be defined inline to a control definition using property element syntax, and thus will apply to that control instance only. For example:

<TextBox>
    <TextBox.Template>
        <!-- Control template definition can go here -->
    </TextBox.Template>
</TextBox>

Control Template Structure

Let's now take a look at exactly what a control template is and how it is structured. Often you will hear this structure referred to as the parts and states model.

At its simplest, a control template simply defines the XAML that makes up the static presentation of the template that never changes, for example:

<ControlTemplate TargetType="Button">
    <Grid>
        <!-- etc -->
    </Grid>
</ControlTemplate>

Note

In Chapter 11, "Creating Custom Controls," we'll go through the structure of control templates in more detail as we look at how to build custom controls.

Visual States

It's rare that a control will have a single static appearance, as almost all controls will change their appearance in some way (such as when it has focus or is disabled). In that case, we would define a base look for the control upon which changes to the control's appearance would be made when appropriate, but we also include the elements that would be visible in the alternative states even if not visible in the base state (with their visibility set to collapsed or opacity set to 0).

For example, a button looks a particular way when it is placed on a form (its default state). Then when it has the focus, is disabled, pressed, hovered over, and so on, its appearance will be updated accordingly. This is where Visual States come in—each visual state defined describes how the base look of the control will be altered when that state is active to achieve the appearance of the control for that state. This essentially involves altering the elements that make up the base look for the control (e.g., changing the color, visibility, or opacity of an element) to visually indicate that the control is in that state. In other words, we define each state in our control template and what changes need to be made to the base look to achieve the desired appearance indicating that state. These changes are actually defined as animations, as will be discussed in the next section ("State Transitions").

What triggers a state change on a control? Essentially, the control behavior (i.e., the code for the control) determines this based on the events it receives and/or the value assigned to one (or more) of its properties. For example, when the user clicks a button and holds the mouse button down (in response to the MouseDown event, which would mean the button is in the Pressed state), then the button needs to change its visual state to indicate as such. Alternatively, the button may be disabled (IsEnabled="false"), in which case the button needs to indicate that as its state (the Disabled state). The control needs to be able to determine what state it should be in response to each situation, but then it delegates to the Visual State Manager to update the appearance of the control accordingly.

Note that no changes should be made to the visual appearance of the control from the code; all presentation details on a per-state basis should be defined within the control template only.

You may also want to have a constant animation for the control while it is in a particular state (such as a button pulsing when the mouse is over it). This is known as in-state animation. This is achieved using a storyboard containing various animations that change the property values of elements within the control over a given duration (and will generally be set to continually repeat while the control is in that state).

A simple example of animating a property on an element within the control is demonstrated in the following example. This animation is used to make the button appear to be pressed changing the Opacity property of the PressedBorder element to 1 (essentially making that element visible).

<VisualState x:Name="Pressed">
    <Storyboard>
        <DoubleAnimationUsingKeyFrames
                        Storyboard.TargetProperty="(UIElement.Opacity)"
                        Storyboard.TargetName="PressedBorder">
            <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

Note

Each state must exist within a state group, as will be described shortly.

A full discussion of implementing animations is beyond the scope of this book, although you will find further examples in Chapter 11, "Creating Custom Controls."

State Transitions

A control moves from state to state via a state transition. State transitions can be represented in the control template using the following:

  • An explicitly defined animation defined within a storyboard (in the same way as in-state animations) over a given duration, for example:

    <VisualTransition GeneratedDuration="0:0:2" From="Inactive" To="Active">
        <Storyboard>
            <DoubleAnimation From="0" To="1" d:IsOptimized="True"
                            Storyboard.TargetProperty="(UIElement.Opacity)"
                            Storyboard.TargetName="LayoutRoot" />
        </Storyboard>
    </VisualTransition>
  • An automatic transition that smoothly animates the elements in the control between their configuration in each state over a given duration, in a process managed by the Visual State Manager, for example:

    <VisualTransition GeneratedDuration="0:0:2" From="Inactive" To="Active" />

Note

State transitions should (as a general rule) have a very short duration (no more than half a second) so as to not slow the user's interaction with the application.

Visual State Groups

We need to take into account one more complexity, and that's when a control can be in more than one state at the one time. For example, one state a button is in may be the Focused state (indicating the button has input focus), but it may also be in the Pressed state (where the button has been clicked and the mouse button hasn't yet been released). So how do we represent both states visually at the same time? Well, this is possible by having the states exist in different visual state groups. The use of visual state groups means that we can group related states together. Although only one in each group can be active at the one time, multiple states can be active across all the defined groups, and the control's appearance can indicate each of these together. So as per the previous example, the base look is updated to indicate the button is pressed, and the focus rectangle will be drawn to indicate the button has focus.

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="CommonStates">
        <!-- Define common states here -->
    </VisualStateGroup>
    <VisualStateGroup x:Name="Focused">
        <!-- Define focused states here -->
    </VisualStateGroup>
    <VisualStateGroup x:Name="Pressed">
        <!-- Define pressed states here -->
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Template Parts

The final concept to understand is that of template parts. A control may need to reference certain visual elements that belong to it in the code for that control (i.e., the behavior management code). Because of the strict separation between the behavior and the presentation and the ability for an alternative control template to be applied to the control, these elements need to be defined as required elements in any control template that is applied. These elements are known as template parts.

Theming

Theming (sometimes also known as skinning) is essentially the process of either styling or retemplating control types to customize their appearance (overriding their default styles or control templates). Themes are generally designed as a way of maintaining the look of the controls in the application in a single location in your project (ensuring consistency across your application and simplifying maintenance). However, they are also particularly useful when creating packaged software that should make use of corporate colors and display the customer's branding.

Based on the defined theme, the styles and control templates within that theme are automatically applied to their corresponding control instances (usually using implicit styles) wherever they may appear throughout the application. For example, you might have a number of themes that completely change the appearance of buttons. You might have a resource dictionary for each theme and define a different button control template for in each, and all the buttons in your application will automatically use the control template from the selected theme file rather than their default one.

Creating a Custom Theme

You can create your own theme file by creating a resource dictionary, placing all of your style resources in it, and merging it with the application's resources (as detailed earlier in the chapter). You can also define this resource file in a separate assembly, which you can then use in other projects (also described earlier).

You can define a new control template in the style resource to completely change the look of the control. Assign it to the control's Template property defined in the style, like so:

<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <!-- Control template goes here -->
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

If you make this style resource an implicit style (as demonstrated), all controls of the specified target type for the style will automatically have the control template applied (thus resulting in a theme-like behavior).

Silverlight Toolkit Themes

The Silverlight Toolkit includes an array of predefined themes that you may like to use in your project that retemplate the standard Silverlight controls (and the Silverlight Toolkit controls) to provide a new distinct look to your application. You can use these as they are or modify them to suit your own tastes. More information can be found on the Silverlight Toolkit's CodePlex site at http://silverlight.codeplex.com.

Silverlight Navigation/Business Application Themed Project Templates

Microsoft has started to release project templates that both restructure the visual layout of the application and retheme all the core Silverlight and Silverlight Toolkit controls (in other words, define new control templates for all these controls).

You can download and install these from the Visual Studio Online Gallery, via Visual Studio's Extension Manager. From the Online Gallery, navigate to the Templates

Silverlight Navigation/Business Application Themed Project Templates

You will find a project template for each theme you install in the Silverlight category of Visual Studio's New Project dialog, which you can then use when creating a project.

New themes will be released over time but, at the time of this writing, include the following:

  • Accent Color

  • Cosmopolitan

  • Windows 7

Icons and Images

Effective use of icons and images throughout your application can really enhance its visual appeal. Designing quality icons is really the job of a graphics designer, but if you don't have the budget for a graphics designer, there is still the viable (and relatively cheap) option of purchasing a stock icon library. Most libraries come as raster files (such as .png files), though some companies are starting to include or sell separately the original vector images.

Note

While .png files work perfectly well in Silverlight, in some instances, you may prefer to use vector (i.e., XAML–based) images instead. Vector images are scalable without losing quality, can be modified easily, and are often smaller than the equivalent raster image (depending on the complexity of the image). However, vector images are also more CPU intensive, so you need to choose the appropriate format for your particular requirements. As a general rule, for small images (such as icons) that don't need to be scaled raster images are a better choice. For larger images (especially those that will change size), vector images may better suit.

Note that vector icons often come as Adobe Photoshop (.psd), Adobe Illustrator (.ai), or Scalable Vector Graphics (.svg) files and need to be converted to XAML (possibly losing some definition along the way) to be used within a Silverlight application. There is a plug-in available for Adobe Illustrator to export to XAML (if you have Adobe Illustrator), or you can open these files from within Expression Blend (using the File

Icons and Images

If you do buy icons or images formatted as XAML, ensure that they are formatted for Silverlight and not WPF (the file formats differ slightly, so if they are formatted for WPF, they will not be usable in Silverlight without modification). That said, if the Expression Design file type is also included, you can use that to export a new XAML file targeting Silverlight instead.

Animation

Once you've got the look of your application right, you can apply some animation effects to give it a bit of additional flair. Animating certain aspects of your user interface (such as page transitions) can add a certain pizzazz to your application and add to its "wow" factor.

However, you should use animations sparingly, so you do not distract users from their primary task when using your application. Animation can impress the user the first couple of times but can quickly become an annoyance. In business applications in particular, you must be aware of this as users will often spend considerable time in their working day with the application, and poorly implemented animations get old quickly. Transition animations (if you decide to use them) should be fast and not slow the user's interaction with the application.

Animations use storyboards to define the times at which various parts of the animation start and stop. Silverlight then handles the process of getting from one frame to another between the animation's start and stop time.

Creating animations is a huge topic and beyond the scope of this book. If you are creating animations, Expression Blend is an essential tool to help you in this task, with a lot of functionality geared toward designing animations.

Pixel Shaders / Effects

Pixel shaders enable you to add effects to Silverlight controls (by modifying the pixels of their rendered output) before displaying them on the screen. Typical effects include shadows, blurs, reflections, and color alteration, but the options are almost endless.

There are two pixel shaders included in the Silverlight 4 runtime:

  • DropShadowEffect

  • BlurEffect

Applying one of these effects is an easy as assigning the pixel shader to the Effect property of a control. The following example demonstrates assigning a drop shadow to a control (with the result shown in Figure 9-1):

<Button Content="Shadow" Width="75" Height="23">
    <Button.Effect>
<DropShadowEffect Opacity="0.5" />
    </Button.Effect>
</Button>
A button with a drop shadow effect

Figure 9.1. A button with a drop shadow effect

You can create your own pixel shaders using the High-Level Shader Language (HLSL), which you then need to compile into a .ps file (using the fxc command-line tool included with the DirectX SDK). However, a quick web search will probably turn up a pixel shader that provides the effect that you are after; many are available for download.

Note

Pixel shader effects are rendered in software. Generally, they can be rather CPU intensive to render, so you should use them sparingly to avoid negatively affecting the performance of your application.

Miscellaneous Styling Tips

Here are a few miscellaneous tips that you may find useful when designing your style resources.

Defining Constants in XAML

In instances where you want to maintain a set of constant values that can be used by multiple controls or style resources but maintained in a single location, you can simply define those values as resources along with a key you can use to reference them. For example, here we are defining a color constant that we can use:

<SolidColorBrush x:Key="BackgroundColorResource" Color="LemonChiffon "/>

You can then assign this resource directly to a control (using the StaticResource markup extension):

<TextBox Background="{StaticResource BackgroundColorResource}" />

Or you can use it in a style resource definition:

<Style x:Key="UserFieldsStyleBase" TargetType="TextBox">
    <Setter Property="Margin" Value="2" />
    <Setter Property="Background"
            Value="{StaticResource BackgroundColorResource}" />
</Style>

This tip can be particularly useful when defining theme files, where you may define a core color scheme using constants that you can maintain in one place and simply change their values between theme files.

Restoring a Control's Default Style

If you have an implicit style being applied to a control that you do not wish to have any styling applied, you can stop the style being applied by setting the Style property of the control to null, for example:

<TextBox Style="{x:Null}" />

This control will retain its default style instead.

Summary

In this chapter, you learned the fundamentals of styling and templating Silverlight controls. Note that styles shouldn't be randomly defined as required but designed with a view of how they fit into the overall look of your user interface. When styling an application, it is best to take a wholistic view of the process and actually design how the styles will be applied across the application, rather than taking a piecemeal approach (assuming the user experience design process has taken place by this stage, providing the framework for our visual structure and the flow of the user interaction). In Chapter 11, "Creating Custom Controls," we'll look at actually building controls that can be styled and template using this model.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset