Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / XAML

Silverlight Visual States Sample

Rate me:
Please Sign up or sign in to vote.
4.50/5 (8 votes)
8 Apr 2009CPOL3 min read 32.4K   339   16  
Interesting aspect of Silverlight visual states and how they can be used in controls.

Introduction

In this article, I want to illustrate an interesting aspect of Silverlight visual states and how they can be used in controls. You can read my blog here: Cellbi Blog.

It is not a secret that one of the key features in Silverlight controls is an ability to declare different states for a control and specify transitions between them.

Each transition between states can take time for animation, and often, it is necessary to know when a transition is really finished. Let us suppose that we've spent a couple of hours and prepared a simple button in Blend. Something that looks like the following picture ;-)

StateEventsExSource

The button above consists of three parts: LayoutRoot (a grid with width and height bound to the "Width" and "Height properties of the control), Host (a button background with color property bound to the "Background" property of the control), and Content (a green arrow).

Visual States in XAML

Here is the result of such efforts in xaml code, which specifies simple style for the button.

XML
<vsm:VisualStateManager.VisualStateGroups>
  <vsm:VisualStateGroup x:Name="CommonStates">
    <vsm:VisualStateGroup.Transitions>
      <vsm:VisualTransition GeneratedDuration="00:00:00.4000000" To="MouseOver"/>
      <vsm:VisualTransition GeneratedDuration="00:00:00.4000000" To="Play"/>
      <vsm:VisualTransition GeneratedDuration="00:00:00.4000000"/>
    </vsm:VisualStateGroup.Transitions>

    <vsm:VisualState x:Name="Normal">
      <Storyboard/>
    </vsm:VisualState>
    <vsm:VisualState x:Name="MouseOver">
      <Storyboard>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
            Duration="00:00:00.4000000"
            Storyboard.TargetName="Host"
            Storyboard.TargetProperty="(UIElement.Opacity)">
          <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Play">
      <Storyboard>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
            Duration="00:00:00.4000000"
            Storyboard.TargetName="Host"
            Storyboard.TargetProperty="(UIElement.Opacity)">
          <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
  </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

Now, we need to add behaviour logic to this button. It should have two methods: Start and Stop. When the mouse moves over the button, the host should change its opacity. When the Stop method is called or the button is simply clicked, the content should start rotation - the play state of the button.

Working with Visual States from C# Code

Ffrom the point of implementation, this can be done in the following way. As you can see from the picture, the button has three states: "Normal", "MouseOver" and "Play". When the mouse pointer is moved over the control, we should start transition to the MouseOver state, and when the button is clicked, we should start transition to the Play state, and only after that, we start the rotation of the content.

Please note: "only after that" start the rotation of the content ;) The problem is that transitions between states can take time. And, if you start rotation of the content immediately after the button is clicked - it will occur in parallel mode with the transition, and trust me, it will look really ugly. So, to avoid this, we definitely should start the rotation after the transition is finished.

Silverlight has an easy way to do exactly this. We can use the visual state manager and visual states. The XAML code contains a VisualStateManager which declares VisualStates and Transitions. So, to implement our task, we simply need to get access to the VisualStateGroups in the OnApplyTemplate method override and handle several events. Let's take a look how the code would look like:

C#
public override void OnApplyTemplate()
{
  base.OnApplyTemplate();

  FrameworkElement root = 
    GetTemplateChild("LayoutRoot") as FrameworkElement;

  .........

  commonStatesGroup = GetVisualStateGroup(root, "CommonStates");
  HookVisualStateGroupEvents(commonStatesGroup);
}

VisualStateGroup GetVisualStateGroup(FrameworkElement root, string groupName)
{
  if (root == null)
    return null;

  IList groups = VisualStateManager.GetVisualStateGroups(root);
  if (groups == null)
    return null;

  foreach (VisualStateGroup gr in groups)
    if (gr != null && gr.Name == groupName)
      return gr;

  return null;
}

void HookVisualStateGroupEvents(VisualStateGroup group)
{
  if (group == null)
    return;
  group.CurrentStateChanged += group_CurrentStateChanged;
}

void group_CurrentStateChanged(object sender, 
           VisualStateChangedEventArgs e)
{
  if (e.NewState != null && 
      e.NewState.Name == "Play")
    OnStarted();
}

Now, let's see what is done in the above code. First, we get access to the "CommonStates" visual group in the OnApplyTemplate method, and then simply subscribe to the CurrentStateChanged event. VisualStateChangedEventArgs in the handler gives us only three properties: Control, OldState, and NewState. However, this is all we need in this handler. ;-) When our event handler is called, we can say that the control was animated and we know which states the animation was done for. From this point, we know that the state of the control was changed and we can start content rotation.

I hope this sample will be useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
I'm excited about computers and programming, since my school days. I have master's degree in software development and at the moment I'm a software developer at Cellbi Software.

Comments and Discussions

 
-- There are no messages in this forum --