Windows Presentation Foundation

Hello, WPF

WPF from Scratch
Navigation Applications
Content Model
Layout
Controls
Data Binding
Dependency Properties
Resources
Styles and Control Templates
Graphics
Application Deployment
Where Are We?

Layout

Introduction
Layout Basics
DockPanel
StackPanel
Grid
Canvas
Viewbox
Text Layout
Common Layout Properties
When Content Doesn't Fit
Custom Layout
Where Are We?

Controls

Introduction
What Are Controls?
Handling Input
Built-In Controls
Where Are We?

Data Binding

Introduction
Without Data Binding
Data Binding
Binding to List Data
Data Sources
Master-Detail Binding
Where Are We?

Styles and Control Templates

Introduction
Without Styles
Inline Styles
Named Styles
Element-Typed Styles
Data Templates and Styles
Triggers
Control Templates
Where Are We?

Resources

Introduction
Creating and Using Resources
Resources and Styles
Binary Resources
Global Applications
Where Are We?

Graphics

Introduction
Graphics Fundamentals
Shapes
Brushes and Pens
Transformations
Visual-Layer Programming
Video and 3-D
Where Are We?

Animation

Animation Fundamentals
Timelines
Storyboards
Key Frame Animations
Creating Animations Procedurally
Where Are We?

Custom Controls

Introduction
Custom Control Basics
Choosing a Base Class
Custom Functionality
Templates
Default Visuals
Where Are We?

ClickOnce Deployment

A Brief History of Windows Deployment
ClickOnce: Local Install
The Pieces of ClickOnce
Publish Properties
Deploying Updates
ClickOnce: Express Applications
Choosing Local Install versus Express
Signing ClickOnce Applications
Programming for ClickOnce
Security Considerations
Where Are We?

Resources and Styles

6.2. Resources and Styles

WPF's styling mechanism depends on the resource system to locate styles. As you already saw in Chapter 5, styles are defined in the Resources section of an element and can be referred to by name, as shown in Example 6-18.

Example 6-18. Referencing a Style resource
<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

    <Window.Resources>
        <Style x:Key="myStyle">
            <Setter Property="Button.FontSize" Value="36" />
        </Style>
    </Window.Resources>

    <Grid>
        <Button Style="{StaticResource myStyle}">Hello</Button>
    </Grid>
</Window>

However, it is also possible to define a style that is applied automatically to an element without the need for the explicit resource reference. This is useful if you want the style to be applied to all elements of a particular type without having to add resource references to every element. Example 6-19 shows a version of Example 6-18 modified to take advantage of this.

Example 6-19. Implicit use of a Style
<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

    <Window.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Button.FontSize" Value="36" />

        </Style>
    </Window.Resources>

    <Grid>
        <Button>Hello</Button>
    </Grid>

</Window>

Notice that the Button no longer has its Style property specified. However, the style will still be applied to the button because of its TargetType. Instead of defining a key, the style now has a TargetType set with the x:Type markup extension, which instructs XAML to provide a System.Type object for the named class.

If a FrameworkElement does not have an explicitly specified Style, it will always look for a Style resource using its own type as the target type.

If you were to create some non-Style resource, such as a SolidColorBrush and set its x:Key to be the type of some UI element, an error would occur if you tried to use that element type. This is because when you create a Style with a TargetType and do not specify the x:Key, the x:Key is implicitly set to be the same as the TargetType. This key is used to locate the style. So, in general, you should avoid setting the x:Key to a Type object.


Because elements look for their styles in resources, you can take advantage of the resource scoping system. You can define a style resource at a local scope if you just wish to affect a small number of elements, or at a broader scope such as in Window.Resources, or at application scope. And styles may even be drawn from the system scope. This relationship between styling and resources is the key to both skinning and theming.

6.2.1. Skins and Themes

Skinning and theming are both techniques for controlling the look and feel of a UI. A theme is a system-wide look, such as the Classic Windows 2000 look, or the Windows XP "Luna" theme. A skin is a look specific to a particular application, such as the distinctive styles available for media programs like WinAmp and Windows Media Player.

Both skins and themes can be implemented in WPF as a set of resources that apply the required styles to controls. By using the convention that the resource name is the Type for the control to which it applies, styles will apply themselves consistently and automatically. These styles will usually set the Template property in order to manage the appearance of the control and may also set other properties, such as those for font handling. (Templates were discussed in Chapter 5.) The main difference between a skin and a theme is one of scope: a skin would typically be stored in the application's Resources property, while a theme lives at the system scope and is not directly associated with any one application.

In the version of WPF available at the time of writing, there was no documented way in which to add a new theme. However, an understanding of how themes work is useful in order to understand how controls get their default appearance.


Since a skin's purpose is to control the appearance of a particular application, it may well provide more than just styles for standard controls; it might define various other named resources for use in specific parts of the application. For example, a music- player application might present a ListBox whose purpose is to present a list of songs. A skin might well want to provide a particular look for this list without necessarily affecting all listboxes in the application. So the application would probably set that ListBox to use a specific named style, enabling the skin to define a style for just that ListBox. In that particular case, the provision of such a specific style might be optional, but in other circumstances, the application might require the skin to provide certain resources. For example, if the application has a toolbar, the skin might be required to provide resources defining the graphics for that toolbar.

Also, a theme applies to all applications, so it must provide templates and styles for all control types. By contrast, a skin is application-specific, so it doesn't necessarily have to provide a comprehensive set of styles. If the application doesn't use every single control type, the skin needs to supply styles only for the controls the application uses. Examples 6-20 and 6-21 show the XAML and code-behind for an extremely simple skin.

Example 6-20. BlueSkin.xamla very simple skin
<ResourceDictionary x:Class="SimpleSkin.BlueSkin"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    >
    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Blue" />
        <Setter Property="Foreground" Value="White" />
    </Style>

</ResourceDictionary>

Example 6-21. BlueSkin.xaml.cscode-behind for a very simple skin
using System;
using System.Windows;

namespace SimpleSkin {

    public partial class BlueSkin : ResourceDictionary {

        public BlueSkin( ) {
            InitializeComponent( );
        }
    }
}

This just sets the foreground and background for a Button. A more complex skin would target more element types and set more properties. Most skins include some Template property setters in order to customize the appearance of controls. But even in this simple example, the underlying principles remain the same. Example 6-22 shows a UI, and Example 6-23 shows the corresponding code-behind that allows skins to be switched. (This example assumes that two skin classes, BlueSkin and GreenSkin, have been defined using the technique shown in Example 6-20.)

Example 6-22. Window1.xamlswitching skins
<Window x:Class="SimpleSkin.Window1" Text="SimpleSkin"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

    <Grid Margin="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />

        </Grid.RowDefinitions>

        <RadioButtonList x:Name="radioSkins">
            <TextBlock>Green</TextBlock>
            <TextBlock>Blue</TextBlock>

        </RadioButtonList>

        <Button Grid.Row="1">Hello</Button>
    </Grid>
</Window>

Example 6-23. Window1.xaml.csswitching skins code-behind
using System;
using System.Windows;
using System.Windows.Controls;

namespace SimpleSkin {

    public partial class Window1 : Window {

        public Window1( ) {
            InitializeComponent( );

            EnsureSkins( );

            radioSkins.SelectionChanged += SkinChanged;
        }

        static ResourceDictionary greenSkin;
        static ResourceDictionary blueSkin;
        static bool resourcesLoaded = false;

        private static void EnsureSkins( ) {
            if (!resourcesLoaded) {
                greenSkin = new GreenSkin( );
                blueSkin = new BlueSkin( );

                resourcesLoaded = true;
            }
        }

        private void SkinChanged(object o, SelectionChangedEventArgs e) {
            switch (radioSkins.SelectedIndex) {
                case 0:
                    Application.Current.Resources = greenSkin;
                    break;
                case 1:
                    Application.Current.Resources = blueSkin;
                    break;
            }
        }
    }
}

This SimpleSkin class contains some code to ensure that the skins get created just once. The code that changes skins simply sets the application resource dictionary to be the one for the selected skins. (The source for the second skin, GreenSkin, is not shown. It looks almost identical to Example 6-20, only using green instead of blue.) The styling and resource systems react automatically to the change in resources, updating all of the affected controls when you switch skins, so this is all the code that is required. Figure 6-5 shows the code in action.

Figure 6-5. Changing skins (Color Plate 16)


There is one slight snag with switching skins this way. If you have any resources stored at the application scope other than the skin resources, they will be lost when switching skins. Currently, the only solution to this is to make sure each skin contains a copy of any non-skin-specific, application-scope resources. The best way to do this is to keep non-skin-specific resources in a separate class and merge them into the skin resources. The current build of WPF has no support for merging resource dictionaries automatically. WPF team members have indicated they are considering easier ways of doing this in a future release, but in the current preview, you must do this manually, as Example 6-24 shows.

Example 6-24. Merging resources
ResourceDictionary skinResources = new FooSkinResources( );
ResourceDictionary nonSkinAppResources = new DrawingResources( );

foreach (DictionaryEntry de in nonSkinAppResources) {
    skinResources.Add(de.Key, de.Value);
}

You would add code like this to the method in which you load the resources. In Example 6-23, you would perform this resource merging in the EnsureSkins method, merging the non-skin application resources into both the blue and the green skins.


©2008 FAQ - WPF Labs - Discuss - Terms of Use - Privacy Policy - About WPF
- Interview Questions - Sharepoint Articles - Interview Questions Resource Library - All about LINQ - MS Knowledgebase Articles - Electronics and Hardware discussions