DevCity.NET - http://devcity.net
How To Use The Visual State Manager(VSM) In Silverlight 2
http://devcity.net/Articles/375/1/article.aspx
Ged Mead

Ged Mead (XTab) is a Microsoft Visual Basic MVP who has been working on computer software and design for more than 25 years. His journey has taken him through many different facets of IT. These include training as a Systems Analyst, working in a mainframe software development environment, creating financial management systems and a short time spent on military laptop systems in the days when it took two strong men to carry a 'mobile' system.

Based in an idyllic lochside location in the West of Scotland, he is currently involved in an ever-widening range of VB.NET, WPF and Silverlight development projects. Now working in a consultancy environment, his passion however still remains helping students and professional developers to take advantage of the ever increasing range of sophisticated tools available to them.

Ged is a regular contributor to forums on vbCity and authors articles for DevCity. He is a moderator on VBCity and the MSDN Tech Forums and spends a lot of time answering technical questions there and in several other VB forum sites. Senior Editor for DevCity.NET, vbCity Developer Community Leader and Admin, and DevCity.NET Newsletter Editor. He has written and continues to tutor a number of free online courses for VB.NET developers.

 
by Ged Mead
Published on 6/26/2009
 

This article walks you through the steps involved in using The Visual State Manager in Silverlight 2.

Most articles seem to use the button as the demonstration element - probably because that makes things very easy.  But as soon as you move away from the small core set of elements such as button that have States preset for you, you will find that you need a slightly different approach.

In this article, I will cover both situations.


Setting States on a Button

Introduction
If you have used WPF, you will be familiar with the concept of Triggers, a mechanism that allows for properties to be changed in reaction to some activity or state. Silverlight 2 takes a different approach and uses States. In this context, the State of an element represents its look at a specified time. The 'specified time' is defined by some form of action (or, to be totally accurate, inaction). As a simple example, the mouse entering the surface area of the element is an action for which you can define a State. Inaction can be thought of as the 'Normal' State - that is, the default look of the element, not accessed in any way by the user.

The Visual State Manager (VSM) is a Class that allows you to create, edit and use States. Without doubt, the easiest way of dealing with the VSM is by using Expression Blend. It is of course possible to create everything by hand in Visual Studio. At the time of writing, when Silverlight 2 and Visual Studio 2008 are the latest RTM versions, unless you have a lot of experience with XAML, I don't recommend that approach. If you don't have Expression Blend, you can download a 30 Day trial copy from here. The rest of this article assumes that you have access to Expression Blend 2 and any version of Visual Studio 2008, including the free Express Edition.

Setting States on a Button
As this is a fairly easy way of introducing the tools and the concept the first control we will use is the button. Here are the steps:

  • Run Microsoft Expression Blend 2.
  • Choose the "New Project" option.
  • Name the Project 'ButtonVSM'.
  • Select your preferred choice of code-behind language (Visual Basic or Visual C#)
  • Click on the Silverlight 2 Project icon.
  • Click OK.

The next stage is to drag a button on to the Artboard.

  • Click on the Button icon in the Toolbar (Second from bottom).
  • Left mouse click and drag on the Artboard to create a button.

In the main Expression Blend screen you will see the Interaction pane. On the left hand side of this pane is the information on States. You might expect that if you have the button selected that its States (if there are any) would now be displayed. If you try this, you will find that this is not the case and the list of States remains bewilderingly empty. The reason is that the States are part of the Control Template, and so you need to access the button's Control Template in order to get to the States.

All you need to do is:

  • Right click on the button on the Artboard.
  • Select Edit Control Parts(Template).
  • Select Edit a Copy.
  • Accept the default Name.
  • Accept the default 'Define In' location.
  • Press OK.


  


A couple of things happen once you have pressed OK.
One of them is very obvious - the list of States for the button are now visible in the Interaction/States pane. The second one is not quite so obvious - In the Objects and Timeline pane, the UserControl tree has been replaced by the Control Template tree for this button object.


  


Dealing with the States first, try left clicking on each of the four Common States in turn. You will see slight changes to the background color of the button, depending on which particular State you have chosen.

As soon as you clicked on the first State, the 'State Recording in On' message appears above the Artboard. This means that you are now able to change the look of the button when it is in one or other of the States. As an experiment, we will change the size of the button when the mouse moves on to it - that is, when the MouseOver State exists.

  • Select the 'MouseOver' State in the States list.
  • Very Important: Select the 'grid' element in the Objects and Timeline list. By default this will often be set on 'FocusVisualElement'.
  • You can check that the grid is the selected item as it will have a light yellow border around it.
  • With the grid selected, go to the Properties pane in the main Blend window.
  • As a double check, you will see the Name property is 'grid' and Type is 'Grid'.
  • Scroll down the Properties pane until you reach 'Transform'.
  • Select the ScaleTransform icon (an arrow coming out of a square).
  • Change the value of X to 1.05.
  • Change the value of Y to 1.05.
  • Press ENTER.

In the Interaction/Objects and Timeline pane, note the appearance of some arrows in red circles. If necessary click on these arrows so that you can see the detailed list.


  


To preview your change, select the various States in the States list and see the appearance on the Artboard. To test your changes in action, press F5 to run the project. When you move the mouse over the button, it will increase in size by 5%. It will return to its normal size when you move the mouse off the button. You will see that the size change is immediate. There is however an easy way of turning this into a smoother transition

 

Transitions

Still working on our MouseOver State, the next step is have the increase and decrease in size take place over a duration of 0.3 of a second. This is done by adding Transitions to the State.

First, we will work on the size increase.

  • In the States list, select MouseOver State.
  • Click on the 'Add Transition' icon at the right hand side. (Arrow and Plus symbol icon).
  • Select the '* to MouseOver' item, which represents changes from any other State to MouseOver State.

  

This Transition will now be visible in the States list, directly below the MouseOver State itself. Notice that there is also a Duration setter, current set at zero seconds:



If you place the mouse directly over the '0s' setting the cursor will change to a 4-way icon. Hold down the left mouse button and drag to the right until the value increases to '0.3s'. If you find that too fiddly, simply left-click on it and type in the value of '0.3' and hit the Tab key.

Press F5 to run the project and move the mouse over the button. Notice that the size increase is now spread over the 0.3 of a second. When you move the mouse off the button however, the transition is still immediate. We will deal with that next.

Click the 'Add Transition' icon for MouseOver again. Take a moment to look at the choices. You will see that you can be very precise with these Transitions. That is, you can have different timings depending on which particular States the Transition is moving between. Feel free to add different values to the transitions between the various states if you want to later.
For our starter example, this time select 'MouseOver to *'. Again, change the duration to 0.3 seconds.

Once you have done this, if you use the mouse to select the various States in the States list, as you did previously, you will see the size of the button change when you select or leave MouseOver, but in the Blend Artboard you don't get any indication of the transition. To do this, you need to run the project again. When you move the mouse on and off the button, you will now see that smoother transition.

More Complex Transitions
The example so far only changes one property - the RenderTransform property on the grid in the button's template. You can of course make multiple property changes and have them all take place within the same transition. All you have to do is select the element or sub-element within the ControlTemplate in the Objects and Timeline, make whatever changes you require. As it happens, the button template we are using here isn't a very good candidate for other changes, because its underlying template is quite complex, but you can change some of the Background colors.

But what do you do if, for example, you want to have the same property changed more than once when a State changes? What I mean by that is, what if you want the button Pressed State to create the following effect: The button tilts a couple of degrees clockwise, then a few degrees anti-clockwise, before finally returning to the horizontal position.

Faced with this kind of requirement, you need to work on the Timeline directly (or write reams of complex XAML, of course, if you want to do it the hard way!).

Let's take an example where you want the button to move as follows when the mouse moves over it:

  • Tilt to the right
  • then immediately tilt to the left
  • and finally return to horizontal.

To achieve this result obviously requires more than one RotateTransform. Here are the steps:
First, get ready to edit the template as before:

  • Right click on the button on the Artboard.
  • Select Edit Control Parts(Template).
  • Select Edit a Copy.
  • Change the Name to 'Tilting'.
  • Accept the default 'Define In' location.
  • Press OK.

Next, create the animation. You will see that the list of States will have appeared. Left-click on the 'MouseOver' state to select it. Double-check that the Grid is selected in the Objects and Timeline pane. Then click on the 'Show Timeline' icon in the Objects and Timeline pane:

You will need to make the Timeline more user-friendly, so locate the Timeline Zoom feature and change the value from the default of 100% to something like 400%:

If you haven't created KeyFrames before, you may find the next few steps quite fiddly. I know that I found it frustrating the first few times.
Click and hold the yellow timeline marker, then drag it a short distance to the right - just past the first tick marker in the timeline. Release it. You don't have to be exact about where you release it, because you cannot get a finer adjustment than one-tenth of a second. As you can see from the next screenshot, it shows the play head position being at the 1/10th of a second point. If you have mover the play head marker beyond this point, simply grab it again and move it back to the left.

Then click on the Record KeyFrame icon (highlighted in the screenshot below). The result will be that the yellow marker is set at the 1/10th of a second position and there will be the a white ellipse in line with the Grid, which indicate that changes will be made to the Grid.

You will see that Timeline Recording is on, so the next step is to tilt the button to the right at the 1/10th of a second point. You can do this simply by rotating the button on the Artboard or by setting a value in the Properties pane.

Using the Artboard approach, hover the mouse somewhere near the top right corner of the button. It will change to a curved double headed arrow. Move the cursor around until you see this cursor icon appear. When it does, left-click and drag downwards to rotate the button a short amount.

You can test that you have succeed so far, by left-clicking on the yellow Timeline marker bar and moving it left and right. You should see the angle of the button change as you do this.

To make the button tilt to the left, you follow more or less the same procedure:
Drag the yellow Timeline marker to the right. Stop dragging when it reaches the 0:00:200 marker. Click on the Record KeyFrame icon. Rotate the button anti-clockwise on the Artboard. The finished result when you run it will look better if you use approximately the same angle as you used for the clockwise rotation.


The final step is to return the button to the horizontal position. The steps are similar to the previous ones - create a KeyFrame, this time at 0:00:400. It is actually surprisingly difficult to return the button to absolutely perfect horizontal using the Artboard. This is a case where it makes sense to use the Properties pane.

Click on the Properties pane tab to select it, then scroll down until you find the 'Transform' section. You may need to click on the small arrow by the side of the word 'Transform' to show all the options.

Select the RotateTransform icon:


Change the value of the Angle to '0' by typing it in or by dragging the small control device. Then Press ENTER to confirm the setting.

You can now test the result in Blend again by dragging the Timeline marker. Make any changes you require and then you are ready to give it a run-time test by pressing F5. Once the browser displays the button, move the mouse on and off it to confirm that it all works as it should.

 

Setting States on Other Elements

As you have seen, some elements - such as buttons - will offer you a preset list of States as soon as you begin to edit the ControlTemplate. But if you create your own user control and want to have state changes affect the visuals, then you have to do a little more work yourself.

For our example, we will use a Rectangle element. Start a new Silverlight2 Application project in Expression Blend and drag a Rectangle on to the Artboard. Right-click on the Rectangle. You may expect to see the 'Edit ControlTemplate' menu choices you had for the button, but of course a Rectangle is a simple shape element and not a control, so you don't have this option.

However, this isn't a problem and the approach we take is slightly different. First, go to the States list in the Interaction pane. Select the 'Add state group' icon - see the screenshot:




By default a new state group will be created and named 'VisualStateGroup'.



Overwrite this name with a more meaningful one, such as 'MouseStates'.

Click on the 'Add state' icon next to the 'MouseStates' group:

Overwrite the default name of 'VisualState' with the word 'Normal'. Add a second State and name this one 'MouseEnters'*. You will see that State recording has been turned on, so change the look of the Rectangle in some way while it is in the MouseEnters State. For my example, I have simply changed its color. You can of course make other changes, such as size, rotation and so on, if you want to.

*Note: If you are curious why I don't use the more natural 'MouseEnter', the reason is that it would cause a naming collision when you start to work on the code.

Next, click on the Add Transition icon next to the MouseEnters State. Select the '*->MouseEnters' option. Change the Transition duration to 0.2s.

Press F5 to run the project. Move the mouse over the Rectangle once the browser fires up and loads the Silverlight application.

If you tried this, you may think something has gone wrong, because you don't get the color change you created in the States list. The key difference between what we are doing here and the earlier button example is that you have to wire up the States in code yourself. I encouraged you to try running it now and see it fail so that you will remember what you have to do when you try creating these kind of States yourself later.

The steps and the code are very straightforward. Check that the MouseEnters state is selected in the States list. Then, in the Properties pane, click on the Events button.

A list of Events for the Rectangle will appear. Find the MouseEnters event and enter a name for the event handler you are about to create in code. I have used 'BRMouseEnter'. Press ENTER and Visual Studio will fire up (or will be brought to the front if it is already running).

Visual Studio will display the code-behind file for the project. Not only that, it will have created the skeleton of the event handler for you. The format of the code that needs to go into the event handler is:

VisualStateManager.GoToState(Control Name, Name you assigned to the State, Use Transitions - True or False)

So in our example this will be:

VisualStateManager.GoToState(Me, "MouseEnters", True)

Run the project from Visual Studio and this time when you move the mouse over the Rectangle, the color will change. You will see that when you move the mouse off the Rectangle it doesn't automatically return to the default color - something you may have come to expect if you have used Triggers in WPF.

From what we have covered so far, you will understand that all you need do is to add another State to the list, add any Transitions you want (if any)and this time create an event handler for the MouseLeave event. You use the same code syntax for this event in the code-behind and when you run the project you will get the changes you require as the mouse moves on and off the Rectangle.

You can use this approach for any element that doesn't automatically offer you a pre-built set of States - the Image being an element you may often want to change when the user interacts with it, for example.

Visual State Manager is an easy tool to use once you understand the basics. If you have had problems with it in the past, I hope this article gives you enough step by step detail to help you use it fully in your Silverlight 2 projects.