Printer Friendly Version      Send     
Click to Rate and Give Feedback
MSDN
MSDN Library
Web Development
Silverlight
Controls
 Styling and Templating Overview
Silverlight 2
Styling and Templating Overview
[This topic is pre-release documentation and is subject to change in future releases. Blank topics are included as placeholders.]

Silverlight enables you to easily create an application that has a unique look and feel to distinguish it from other applications. By using styles and templates, you have a lot of flexibility in the appearance of your application. You can make slight changes to its appearance, such as changing the color of the controls and elements to something other than their default value, or more drastic changes, such as changing the shape of buttons. The two classes that assist you in specifying the appearance of your application are Style and ControlTemplate. You use a Style to set property values, and then, when you apply the style to multiple instances of a control, each control uses the property value that you set in the style. If you want to change the appearance of a control beyond setting its properties, you can create a ControlTemplate. A ControlTemplate defines the appearance and visual behavior of a control. Any element that inherits from FrameworkElement can have a style applied to it. Elements that inherit from the control have a ControlTemplate.

You can use a style to set properties once and apply the style to multiple controls, which gives the controls a uniform appearance. When you apply a style to a control, you can still set properties locally on the control, and the property value that is set locally take precedence over the property value set on the style. For example, suppose you want most of the buttons in your application to be red and the font to be 16 pt, but there is one button that needs to be green, but still have 16 pt font. You can create a style that sets the Background property to red and the FontSize property to 16 pt and apply the style to each button. You can then set the Background property of the button that you want to be green. The button's FontSize is still 16 pt (which is set in the style), but the Background property is green because it is set locally.

The following example creates two styles: one for a TextBlock and one for a TextBox. Each style is applied to two instances of a control to create a uniform appearance for each TextBlock and TextBox. Notice that in the style for the TextBox, the Margin property is set to 4, which means that the TextBox has a margin of 4 on all sides. To compensate for the length of the second TextBlock, which is shorter than the first TextBlock because "Last Name" takes less room than "First Name," a value of "6,4,4,4" is assigned to the Margin property on the second TextBox. This causes the second TextBox to align horizontally with the first TextBox.

XAML
<StackPanel>
    <StackPanel.Resources>
        <!--Create a Style for a TextBlock to specify that the
            Foreground equals Navy, FontSize equals 14, and
            VerticalAlignment equals Botton.-->
        <Style TargetType="TextBlock" x:Key="TextBlockStyle">
            <Setter Property="Foreground" Value="Navy"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="VerticalAlignment" Value="Bottom"/>
        </Style>

        <!--Create a Style for a TextBlock that specifies that
            the Width is 200, Height is 20, Margin is 4,
            Background is LightBlue, and FontSize is 14.-->
        <Style TargetType="TextBox" x:Key="TextBoxStyle">
            <Setter Property="Width" Value="200"/>
            <Setter Property="Height" Value="20"/>
            <Setter Property="Margin" Value="4"/>
            <Setter Property="Background" Value="LightBlue"/>
            <Setter Property="FontSize" Value="14"/>
        </Style>
    </StackPanel.Resources>

    <!--Apply the TextBlockStyle and TextBoxStyle to each 
        TextBlock and TextBox, respectively.-->
    <StackPanel Orientation="Horizontal">
        <TextBlock Style="{StaticResource TextBlockStyle}">
            First Name:
        </TextBlock>
        <TextBox Style="{StaticResource TextBoxStyle}"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Style="{StaticResource TextBlockStyle}">
            Last Name:
        </TextBlock>
        <TextBox Style="{StaticResource TextBoxStyle}"  
                 Margin="6,4,4,4"/>
    </StackPanel>
</StackPanel>

Sometimes you want to customize the appearance of your application beyond what setting properties allows you to do. For example, you might want the buttons in your application to be shaped differently than the default. When you replace the appearance of an existing control without changing its functionality, you change the control's skin.

In Silverlight, the skin of a control is defined by its ControlTemplate. Because you create a ControlTemplate in XAML, you can change a control's appearance without writing any code. The Control class has a public Template property that can be set by application developers. The following example creates a custom ControlTemplate for the Button.

XAML
<StackPanel xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
    <StackPanel.Resources>
        <Style TargetType="Button" x:Key="newTemplate">
            <!--Set the Background, Foreground, FontSize, Width, 
                Height, Margin, and Template properties for
                the Button.-->
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Foreground" Value="Navy"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="Width" Value="100"/>
            <Setter Property="Height" Value="40"/>
            <Setter Property="Margin" Value="10"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid x:Name="RootElement">
                            <vsm:VisualStateManager.VisualStateGroups>

                                <!--Define the states and transitions for the common states.
                                    The states in the VisualStateGroup are mutually exclusive to
                                    each other.-->
                                <vsm:VisualStateGroup x:Name="CommonStates">

                                    <!--Define the VisualTransitions that can be used when the control
                                        transitions between VisualStates that are defined in the
                                        VisualStatGroup.-->
                                    <vsm:VisualStateGroup.Transitions>

                                        <vsm:VisualTransition To="MouseOver" Duration="0:0:1" />
                                        <vsm:VisualTransition From="Pressed" To="MouseOver" Duration="0:0:0.01" />

                                        <vsm:VisualTransition To="Pressed" Duration="0:0:0.01" />
                                        <vsm:VisualTransition From="MouseOver" To="Normal"  Duration="0:0:1.5">
                                            <Storyboard>
                                                <ColorAnimationUsingKeyFrames
                                                        Storyboard.TargetProperty="Color"
                                                        Storyboard.TargetName="BorderBrush"
                                                        FillBehavior="HoldEnd" >

                                                    <ColorAnimationUsingKeyFrames.KeyFrames>

                                                        <LinearColorKeyFrame Value="Blue" KeyTime="0:0:0.5" />
                                                        <LinearColorKeyFrame Value="Yellow" KeyTime="0:0:1" />
                                                        <LinearColorKeyFrame Value="#aac" KeyTime="0:0:1.5" />

                                                    </ColorAnimationUsingKeyFrames.KeyFrames>
                                                </ColorAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </vsm:VisualTransition>
                                    </vsm:VisualStateGroup.Transitions>

                                    <!--Define the VisualStetes in this VistualStateGroup.-->
                                    <vsm:VisualState x:Name="Normal" />
                                    <vsm:VisualState x:Name="MouseOver">
                                        <Storyboard>
                                            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                                            Storyboard.TargetProperty="Color" To="Red" />
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="Pressed">
                                        <Storyboard >
                                            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                                            Storyboard.TargetProperty="Color" To="Orange" 
                                                            />
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="DisabledState">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="DisabledRect" 
                                                             Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                                        </Storyboard>
                                    </vsm:VisualState>
                                </vsm:VisualStateGroup>

                                <!--Define the states and transitions for the focus states.
                                    The states in the VisualStateGroup are mutually exclusive to
                                    each other.-->
                                <vsm:VisualStateGroup x:Name="FocusStates">

                                    <!--Define the VisualStetes in this VistualStateGroup.-->
                                    <vsm:VisualState x:Name="Focused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual" 
                                                                           Storyboard.TargetProperty="Visibility" Duration="0">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>
                                    <vsm:VisualState x:Name="Unfocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual" 
                                                                           Storyboard.TargetProperty="Visibility" Duration="0">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Collapsed</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </vsm:VisualState>
                                </vsm:VisualStateGroup>
                            </vsm:VisualStateManager.VisualStateGroups>

                            <!--Create a border that has a different color.-->
                            <Grid.Background>
                                <SolidColorBrush x:Name="BorderBrush" Color="#aac"/>
                            </Grid.Background>

                            <Grid Background="#dde" Margin="4">

                                <!--Create a Rectangle that indicates that the
                                    Button has focus.-->
                                <Rectangle x:Name="FocusVisual" 
                                    Visibility="Collapsed" Margin="2" 
                                    Stroke="#60000000" StrokeThickness="1" 
                                    StrokeDashArray="1.5 1.5"/>

                            </Grid>

                            <!--Use a ContentPresenter to display the Content of
                                the Button.-->
                            <ContentPresenter
                              Content="{TemplateBinding Content}"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                              Padding="{TemplateBinding Padding}"
                              TextAlignment="{TemplateBinding TextAlignment}"
                              TextDecorations="{TemplateBinding TextDecorations}"
                              TextWrapping="{TemplateBinding TextWrapping}"
                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                              Margin="4,5,4,4" />

                            <Rectangle x:Name="DisabledRect" 
                                RadiusX="4" RadiusY="4" 
                                Fill="#A5FFFFFF"
                                Opacity="0" IsHitTestVisible="false" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </StackPanel.Resources>
    <Button Style="{StaticResource newTemplate}" 
            Content="Button1"/>

</StackPanel>

When you create a new template for a control, you redefine its visual structure and visual behavior. Is some cases, the code of a control might refer to parts of the control's ControlTemplate. For example, the code might call a method on an element that is in the template to perform some functionality. This means you must understand how the template and the code relate to each other. That relationship is described by the control contract, which is an agreement between the logical and visual parts of the control. The following example describes the control contract of the Button.

C#
[TemplateVisualState(Name = "Normal", GroupName = "CommonStates")]
[TemplateVisualState(Name = "MouseOver", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")]
[TemplateVisualState(Name = "DisabledState", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")]
[TemplateVisualState(Name = "Focused", GroupName = "FocusStates")]
public class Button : Control
{
    public static readonly DependencyProperty BackgroundProperty;
    public static readonly DependencyProperty BorderBrushProperty;
    public static readonly DependencyProperty BorderThicknessProperty;
    public static readonly DependencyProperty ContentProperty;
    public static readonly DependencyProperty ContentTemplateProperty;
    public static readonly DependencyProperty FontFamilyProperty;
    public static readonly DependencyProperty FontSizeProperty;
    public static readonly DependencyProperty FontStretchProperty;
    public static readonly DependencyProperty FontStyleProperty;
    public static readonly DependencyProperty FontWeightProperty;
    public static readonly DependencyProperty ForegroundProperty;
    public static readonly DependencyProperty HorizontalContentAlignmentProperty;
    public static readonly DependencyProperty PaddingProperty;
    public static readonly DependencyProperty TextAlignmentProperty;
    public static readonly DependencyProperty TextDecorationsProperty;
    public static readonly DependencyProperty TextWrappingProperty;
    public static readonly DependencyProperty VerticalContentAlignmentProperty;

    public Brush Background { get; set; }
    public Brush BorderBrush { get; set; }
    public Thickness BorderThickness { get; set; }
    public object Content { get; set; }
    public DataTemplate ContentTemplate { get; set; }
    public FontFamily FontFamily { get; set; }
    public double FontSize { get; set; }
    public FontStretch FontStretch { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontWeight FontWeight { get; set; }
    public Brush Foreground { get; set; }
    public HorizontalAlignment HorizontalContentAlignment { get; set; }
    public Thickness Padding { get; set; }
    public TextAlignment TextAlignment { get; set; }
    public TextDecorationCollection TextDecorations { get; set; }
    public TextWrapping TextWrapping { get; set; }
    public VerticalAlignment VerticalContentAlignment { get; set; }
}

A control contract has three elements:

  • The public properties that visually affect the control. These are properties that you can set to change the appearance of the control without creating a new ControlTemplate.

  • The UIElement objects that the control's logic uses. For example, the code might handle an event of an element.

  • The VisualState objects that specify the appearance of the control when it is a certain state, and the VisualStateGroup each one belongs to.

The Button does not have UIElement parts in its control contract, but more complex controls do. When a control expects to find a particular UIElement in the ControlTemplate, it uses the TemplatePartAttribute to convey information about the element.

VisualState objects enable you to change the appearance of a control by specifying a Storyboard to apply when the control is in a certain state. The following example shows the VisualState that changes the appearance of a Button; when the mouse is over it the color of the BorderBrush changes.

XAML
<Button Style="{StaticResource newTemplate}" 
              Foreground="Green" Content="Button1"
              FontSize="14"/>
<Button Style="{StaticResource newTemplate}" HorizontalContentAlignment="Left" 
              Foreground="Red" Content="Button2" IsEnabled="False"
              FontSize="18"/>

XAML
<vsm:VisualState x:Name="MouseOver">
    <Storyboard>
        <ColorAnimation Storyboard.TargetName="BorderBrush" 
                        Storyboard.TargetProperty="Color" To="Red" />
    </Storyboard>
</vsm:VisualState>

The VisualState objects of a control can be mutually exclusive to some states, but not to others. For example, a Button can have focus when the mouse over it, or can have focus when the mouse is not over it. Whether the mouse is over the Button does not affect whether it has focus, so the MouseOver state and the Focused state are not mutually exclusive. To indicate which VisualState objects are mutually exclusive to each other, group them in a VisualStateGroup. The following example shows two VisualStateGroup objects for the Button.

XAML
<vsm:VisualStateManager.VisualStateGroups>

    <!--Define the states and transitions for the common states.
        The states in the VisualStateGroup are mutually exclusive to
        each other.-->
    <vsm:VisualStateGroup x:Name="CommonStates">

        <!--Define the VisualTransitions that can be used when the control
            transitions between VisualStates that are defined in the
            VisualStatGroup.-->
        <vsm:VisualStateGroup.Transitions>

            <vsm:VisualTransition To="MouseOver" Duration="0:0:1" />
            <vsm:VisualTransition From="Pressed" To="MouseOver" Duration="0:0:0.01" />

            <vsm:VisualTransition To="Pressed" Duration="0:0:0.01" />
            <vsm:VisualTransition From="MouseOver" To="Normal"  Duration="0:0:1.5">
                <Storyboard>
                    <ColorAnimationUsingKeyFrames
                            Storyboard.TargetProperty="Color"
                            Storyboard.TargetName="BorderBrush"
                            FillBehavior="HoldEnd" >

                        <ColorAnimationUsingKeyFrames.KeyFrames>

                            <LinearColorKeyFrame Value="Blue" KeyTime="0:0:0.5" />
                            <LinearColorKeyFrame Value="Yellow" KeyTime="0:0:1" />
                            <LinearColorKeyFrame Value="#aac" KeyTime="0:0:1.5" />

                        </ColorAnimationUsingKeyFrames.KeyFrames>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </vsm:VisualTransition>
        </vsm:VisualStateGroup.Transitions>

        <!--Define the VisualStetes in this VistualStateGroup.-->
        <vsm:VisualState x:Name="Normal" />
        <vsm:VisualState x:Name="MouseOver">
            <Storyboard>
                <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                Storyboard.TargetProperty="Color" To="Red" />
            </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="Pressed">
            <Storyboard >
                <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                Storyboard.TargetProperty="Color" To="Orange" 
                                />
            </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="DisabledState">
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName="DisabledRect" 
                                 Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
            </Storyboard>
        </vsm:VisualState>
    </vsm:VisualStateGroup>

    <!--Define the states and transitions for the focus states.
        The states in the VisualStateGroup are mutually exclusive to
        each other.-->
    <vsm:VisualStateGroup x:Name="FocusStates">

        <!--Define the VisualStetes in this VistualStateGroup.-->
        <vsm:VisualState x:Name="Focused">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual" 
                                               Storyboard.TargetProperty="Visibility" Duration="0">
                    <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </vsm:VisualState>
        <vsm:VisualState x:Name="Unfocused">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual" 
                                               Storyboard.TargetProperty="Visibility" Duration="0">
                    <DiscreteObjectKeyFrame KeyTime="0">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </vsm:VisualState>
    </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

You can also specify how a control should transition between states. For example, you can set the Duration property to specify that the transition from one state to another should take a certain amount of time. You can also restrict when a VisualTransition can be applied by setting its To and From properties. The following example creates a transition that occurs only when the control goes from the MouseOver state to the Pressed state.

XAML
<vsm:VisualTransition From="Pressed" To="MouseOver" Duration="0:0:0.01" />

You can create a VisualTransition with different levels of restriction. The following table describes the levels of restriction from most restrictive to least restrictive.

Type of restriction

Value of From

Value of To

From a specified state to another specified state

The name of a VisualState

The name of a VisualState

From any state to a specified state

Not set

The name of a VisualState

From a specified state to any state

The name of a VisualState

Not set

From any state to any other state

Not set

Not set

You can have multiple VisualTransition objects in a VisualStateGroup that refer to the same state, but they will be used in the order that the table above specifies. In the following example, there are two VisualTransition objects. When the control transitions from the Pressed state to the MouseOver state, the VisualTransition that has both From and To set is used. When the control transitions from a state that is not Pressed to the MouseOver state, the other state is used.

XAML
<vsm:VisualTransition To="MouseOver" Duration="0:0:1" />
<vsm:VisualTransition From="Pressed" To="MouseOver" Duration="0:0:0.01" />

You can specify an animation to take place when the VisualTransition occurs. For example, you can specify that a certain animation occurs when the control transitions from the MouseOver state to the Normal State. The following example shows the VisualTransition that occurs when the user moves the mouse away from the button.

XAML
<vsm:VisualTransition From="MouseOver" To="Normal"  Duration="0:0:1.5">
    <Storyboard>
        <ColorAnimationUsingKeyFrames
                Storyboard.TargetProperty="Color"
                Storyboard.TargetName="BorderBrush"
                FillBehavior="HoldEnd" >

            <ColorAnimationUsingKeyFrames.KeyFrames>

                <LinearColorKeyFrame Value="Blue" KeyTime="0:0:0.5" />
                <LinearColorKeyFrame Value="Yellow" KeyTime="0:0:1" />
                <LinearColorKeyFrame Value="#aac" KeyTime="0:0:1.5" />

            </ColorAnimationUsingKeyFrames.KeyFrames>
        </ColorAnimationUsingKeyFrames>
    </Storyboard>
</vsm:VisualTransition>

Preserving the Functionality of a Control's Properties by Using TemplateBinding

The control contract indicates that properties can be used to change the appearance of the control without changing the ControlTemplate. When you create a new ControlTemplate, you still might want to use the public properties to change the control's appearance. The TemplateBinding markup extension binds a property of an element that is in the ControlTemplate to a public property that is defined by the control. In the previous example, the Foreground and FontSize properties of the TextBlock, TextElement, are bound to the properties of MyButton that have the same name. You can create multiple buttons and use the same ControlTemplate, yet set the Foreground and FontSize properties to different values on each button. The following example creates two MyButton controls that use the style that was defined in the previous example. This example sets the Foreground and FontSize properties on each control to different values, so the text inside of each control has a different appearance.

XAML
<Button Style="{StaticResource newTemplate}" 
              Foreground="Green" Content="Button1"
              FontSize="14"/>
<Button Style="{StaticResource newTemplate}" HorizontalContentAlignment="Left" 
              Foreground="Red" Content="Button2" IsEnabled="False"
              FontSize="18"/>

XAML
<vsm:VisualState x:Name="MouseOver">
    <Storyboard>
        <ColorAnimation Storyboard.TargetName="BorderBrush" 
                        Storyboard.TargetProperty="Color" To="Red" />
    </Storyboard>
</vsm:VisualState>

Styles in Silverlight differ from styles in Windows Presentation Foundation (WPF) in the following ways:

  • In Silverlight, you must add x:Key attributes to your custom styles and reference them as static resources. Silverlight does not support implicit styles applied using the TargetType attribute value.

  • In Silverlight, styles cannot be based on other styles. Silverlight does not support the BasedOn attribute.

  • Styles are write-once in Silverlight. You can set a style to override a built-in default style, but attempting to set the same style again will result in an exception. However, you can change the values of individual control properties that have been set within a style. For example, you can set the Control..::.Template property at run time even if this property has been set by a style.

© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker