Yesterday, I showed how I created the first Silverlight control from last week's post. Today, we will take a look at the second control from that post.
Unlike the first control, this control was designed entirely in Expression Blend. Within the LayoutRoot Grid that is created by default, I added a standard Button control. I could have used the same approach as the other Silverlight control: create a Storyboard for the animation when hovering over the Button and then wire up the event handlers to deal with starting and stopping the animation. The problem with that approach is that we would need to consider the animation when the mouse enters, leaves and presses the Button as well as the Button becoming disabled or enabled. The interactivity of the button presents a bit of a problem.
If this was a control being designed for a WPF application, we could use triggers. However, Silverlight does not currently support triggers. Instead, Silverlight 2 Beta 2 introduced the concept of visual state management through the VisualStateManager class. We will save an in-depth discussion of VisualStateManager for another time; for now, consider that we are dealing with a state machine as the Button transitions between states.
Note: The WPF supported by Silverlight typically has been a subset of the full WPF library used by desktop applications. The VisualStateManager is an exception to this rule; however, Microsoft is working on adding support for VisualStateManager to desktop WPF.
To modify the Button to enlarge and change colors when the mouse is hovering over it, I decided to edit the Button's template. The first time that you edit a template, choose to edit a copy of the Button's template. This will create a template based on the Button's default template. The next step is to alter the appearance of the Button when the mouse hovers over it, otherwise known as the MouseOver state. The collection of VisualStates supported by the Button is viewable in the States window below. The various VisualStates are contained within VisualStateGroups; a control will only ever be in one state within a group at a time. So, we can select a state, such as MouseOver, and set the properties that differ from the Button's Base state. Since the VisualStateManager handles changing the Button from one VisualState to another, we do not need to do anything else to cause the Button to switch between VisualStates.

This is all nice, but we really want the transition to the MouseOver state to have some animation to it, rather than a sudden change in size and color (much like a trigger would do). We can add transitions between the VisualStates of a VisualStateGroup and specify the length of the transition. We can also specify that a transition will occur from any state to a specific state or from a specific state to any state. You can see this in the image of the States window above where MouseOver has a transition from and to any state. Setting the MouseOver transitions in this manner cause the Button to grow when the mouse moves over the control and shrink when the mouse leaves. This is a much smoother change in appearance than suddenly becoming bigger and smaller.
To understand what some of this looks like behind the scenes, here is the VisualStateManager portion of the XAML for the Button's template. Notice that the VisualState contains a Storyboard object; with animation, it always comes back to using Storyboards.
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0:0:0.2" To="MouseOver"/>
<vsm:VisualTransition Duration="0:0:0.1" To="Pressed"/>
<vsm:VisualTransition Duration="0:0:0.2" From="MouseOver"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState x:Name="Normal">
<Storyboard/>
</vsm:VisualState>
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames ... >
<SplineColorKeyFrame ... />
</ColorAnimationUsingKeyFrames>
...
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Pressed">
...
</vsm:VisualState>
<vsm:VisualState x:Name="Disabled">
...
</vsm:VisualState>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup x:Name="FocusStates">
...
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>There is definitely more than one way to add animation to a Silverlight control. Yesterday, we looked at using Storyboards to handle a number of animations. Today, we considered using state management and transitions to handle animations within a single control. This approach is very useful when designing custom templates and controls. For a peek at the source code for this Silverlight control, click here.
Note: In Visual Studio, the XAML editor will give you error "The attachable property 'VisualStateGroups' was not found in type 'VisualStateManager'." on the line <vsm:VisualStateManager.VisualStateGroups>. This is a known issue and will not cause any problems during compilation or runtime.


0 comments:
Post a Comment