Introduction to Silverlight control templates

In this blog post we will have a quick look at the main mechanism used for providing interaction visuals to control templates in Silverlight. Instead of using triggers like in WPF, Silverlight provides a system called the Visual State Manager which we can use to change the appearance of a Silverlight control based on the current state that the control is in. In the Silverlight world, each control has various visual states that it can be in such as ‘normal’ or ‘mouse over’. Furthermore, within each control, related states are grouped together and given a group name such as ‘CommonStates’ or ‘FocusStates’.

The first thing to do when making control templates for Silverlight is to include the following namespace reference at the top of the xaml file that will contain the templates.

xmlns:vsm=”clr-namespace:System.Windows;assembly=System.Windows”

Now, lets look at a very simple example of a style that can be applied to a Silverlight button.

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate>
          <Grid>
            <Border Background="{StaticResource ButtonBackground}"
                    BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"
                    BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}" />
            <Border Name="MouseOverBorder" Background="{StaticResource MouseOverButtonBackground}"
                    BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"
                    BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}" Opacity="0" />
            <Border Name="MousePressedBorder" Background="{StaticResource PressedButtonBackground}"
                    BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"
                    BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource TemplatedParent}}" Opacity="0" />
            <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0,5,0" />
            <vsm:VisualStateManager.VisualStateGroups>
              <vsm:VisualStateGroup x:Name="CommonStates">
                <vsm:VisualState x:Name="Normal" />
                <vsm:VisualState x:Name="MouseOver">
                  <Storyboard>
                    <DoubleAnimation Duration="0:0:00.200" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="MouseOverBorder" To="1" />
                  </Storyboard>
                </vsm:VisualState>
                <vsm:VisualState x:Name="Pressed">
                  <Storyboard>
                    <DoubleAnimation Duration="0:0:00.000" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="MousePressedBorder" To="1" />
                  </Storyboard>
                </vsm:VisualState>
              </vsm:VisualStateGroup>
            </vsm:VisualStateManager.VisualStateGroups>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

This style provides interaction visuals for the mouse over and mouse pressed actions of a button. Here you will see that the root element of the control template is a Grid. Within this grid are 3 Border objects. Each Border corresponds to one of the button states and have different background brushes. The first border defines the neutral look of the button and the remaining ones have zero opacity making them invisible. Below the Borders and the ContentPresenter are some lines of code that are using the vsm namespace. The first tag is the VisualStateManager.VisualStateGroups. Within this are the VisualStateGroups containing the VisualStates that we need. The content of a VisualState is a Storyboard object which can contain any number of various animations. The most common animation to use here is the DoubleAnimation as seen in the above style. The double animations here are changing the opacity of the appropriate Border object to 1. This makes the border visible and covers up the neutral border, thus changing the appearance of the button.

Other animations that are useful for Silverlight control templates are ColorAnimation and ObjectAnimation. ColorAnimation is an alternative to using a DoubleAnimation when all you need to do is change the color of something. Though, if your working with gradient paints, DoubleAnimation is much easier. The ObjectAnimation can be used to change the value of any property. This is useful for various tasks such as changing the visibility of the popup within a ComboBox template. Changing the duration property of any of these animations will provide animated transitions from one visual to another as the control changes state.

Other things to notice in the above style is that the ‘Normal’ state is included even though it doesn’t contain any animations. There is a difference between including an empty VisualState, and not including the VisualState at all. In this case, we need to include the ‘Normal’ state to allow the button to return to normal when the mouse leaves. Also, it doesn’t matter if you include the visual state groups before or after the content of the grid. This just depends on your personal preference.

If you need any advice with creating control templates for any of the controls in our Silverlight Elements pack, then let us know and we’ll be there to help.

3 Responses to “Introduction to Silverlight control templates”

  • Introduction to Silverlight control templates…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  • Hi,
    After reading this, one may think that ObjectAnimation can interpolate any type of property, but it can’t. Actually there is no such a thing as ObjectAnimation, there’s only ObjectAnimationUsingKeyFrames, which works with any type of data, but cannot animate transitions between key-frames. It means that animated property changes only when animation gets to another key-frame, but between key-frames there are no changes.

  • Thanks carbronek

    That’s right, I was meaning to write ObjectAnimtationUsingKeyFrames.

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top