The team blog of the Expression Blend and Design
As you probably know, Silverlight and WPF have a runtime piece called the Visual State Manager (or VSM for short). As I’ll describe in this post, VSM and the Expression Blend tooling support for VSM lend a nice clean mental model to the business of visual states and visual state changes for both custom controls and UserControls.
Although chronologically the story begins with the control author, I’ll talk about that aspect later in this post simply because there are more people in the world concerned with the visual stuff than with the logical stuff. The visual aspect begins in Blend, with a set of already-defined visual states organized into groups in the States panel.
You can identify three stages in the design of visual states and transitions. First, the static stage. Here you make each visual state look the way you want it to, and you do so ideally without any thought of transitions. You select a state in the States panel and you change object properties. And speaking of the States panel, this is probably a good time to introduce the idea of state groups.
Visual states are grouped in such a way that a) the states within a state group are mutually exclusive of one another and b) the states contained in any group are independent of the states contained in any other group. This means that one, and any one, state from every group can be applied at the same time without conflict. An example is a check box where the checked states are independent of, and orthogonal to, the mouse states. Changing an object’s property in more than one state within the same group is common practice. For example, you might change a Rectangle’s Fill to different colors in MouseOver, Pressed and Disabled. This works because only one state from the CommonStates state group is ever applied at a time. But changing an object’s property in more than one state group breaks the independent nature of the state groups and leads to conflicts where more than one state is trying to set the same object’s property at the same time. Blend will display a warning icon (with a tooltip containing details) next to any affected state group whenever this conflict situation is detected.
Each state group should contain a state that represents the default state for that group. CommonStates has ‘Normal’, CheckedStates has ‘Unchecked’, and so on. It is a good (and efficient) practice to set objects’ properties in Base such that no changes have to be made in any ‘default’ state. So, for example, you would hide a check box’s check glyph and focus rectangle in Base and then show them in Checked and Focused respectively.
So now you can click through the states to confirm that each looks correct. You can build and run, and test your states, and you might even stop at this stage if you’re happy that the control switches instantly from one state to another. But if instant state switches are not what you want then you can breathe life into your transitions in stage two, the transitions stage. First, add any transitions you want to see, then set transition durations and easing on them, still in the States panel. And again, in very many cases this will be enough for your scenario. What’s interesting for those designers who can stop at this point is that there was no need to open the Timeline and no need to be bothered with the attendant concepts of what a Storyboard is, etc. To keep unnecessary concepts and UI out of your face, by default Blend keeps the Timeline closed when you select a visual state or edit a transition duration. You can of course open it at any time with the Show Timeline button.
Still in the transitions stage, there may be times when you need a property’s value to change during the transition from StateA to StateB but, because of the way StateA and StateB are defined, the property either doesn’t change or doesn’t pass through the desired value. In this case you need to customize that transition. Select the transition and then use the Timeline as normal to define the animations that should take place during the transition.
The last stage is dynamic states. If, for example, you want a blue rectangle to subtly pulse while a control has focus then you need a steady-state animation. I also call them ‘in-state animations’ because the animation happens while you’re ‘in a state’. To do this, just select the state, open the Timeline, and go ahead and keyframe as usual, possibly also selecting the Storyboard and setting repeat behavior and auto reverse.
Now let’s move onto the topic of how states relate to control authoring. Before a designer can begin deciding what states and transitions look like, the control author must decide what states exist. As a control author, your job is not to think about visual states, but logical states. Forget what it looks like; what does it mean? You need to consider all the ways the end user (and possibly other factors such as invalid data) can interact with the control, and from that thinking build out a set of candidate states; and the states are logical at this point because they have no ‘look’. Now’s the time to think about whether your candidate states need factoring. Look for islands of states: closed graphs that don’t link to other states. There are two kinds: orthogonal and nested. Orthogonal islands should be put in their own state group. An example is that of CheckedStates and FocusedStates. There are no transitions between a CheckedStates state and a FocusedStates state, and a control is either checked or not, and focused or not, and there is no dependency between those two aspects. Islands that should be nested have the characteristics that there are no transitions between a StateGroupA state and a StateGroupB state, and the states in StateGroupB are only effective for one state in StateGroupA. For example if StateGroupA contains LoginPageHidden and LoginPageShown, and StateGroupB contains LoginNormal and LoginError, then it’s clear that StateGroupB is only effective during StateGroupA.LoginPageShown. In this case the two state groups are not orthogonal so you may choose not to use state groups. An alternative, and arguably cleaner, design would be to put StateGroupA at one level of hierarchy with StateGroupB defined on a nested control. Another point to bear in mind, related to naming states, is that each state name must be unique for a control type, even across state groups.
When a control initializes, it first has to get itself onto the state graph. This is important. If a control doesn’t do this then it is still in Base after initialization. Base is not a state; it merely represents the control with its local (or ‘base’) property values set, with no states applied. When the mouse pointer first moves over this control it will go to MouseOver but it will go there from Base, so the Normal -> MouseOver transition will not run the first time. This is a subtle bug that the consumer of your control cannot fix by defining Base -> MouseOver, because Base is not a state. So when you author your own templated control or UserControl, you should define a ‘default’ state in each state group. Have the control go to those ‘default’ states when it initializes, and do so with transitions suppressed so that it happens without delay. Once it’s on the state graph, the control is ready for state transitions to occur so now you can implement the event-handlers that trigger the transitions within the state graph.
I hope this post has been useful and has helped clarify some of the less obvious aspects of designing and authoring controls to work well with the Visual State Manager. If you want to see a walkthrough of some of the ideas presented here, you could try my Button styling video.
What are these things – are they different ways of doing the same task? When would I use one in preference to another? Do they all work in all project types?
This post will try to answer those questions by describing the animation and control customization tools that are available to you in Expression Blend 3 + SketchFlow, and discussing what jobs each tool is meant to do. I’ll be classifying project types along two independent axes: WPF or Silverlight, and Blend or SketchFlow.
In the first release of Blend, if you wanted to change the value of a property over time, then the Storyboard was your one option. Using a Storyboard is also known as ‘keyframing’. You create a new Storyboard (or create a BeginStoryboardAction and let that workflow create a Storyboard for you), move the playhead to various times and then use the artboard or the property inspector to change values. Each time you change a value, a keyframe is added to Blend’s Timeline meaning that, at that time, the property has that value. During the interval between keyframes, the property value smoothly takes on intermediate values in a process known as interpolation. By default, the interpolation between two values is linear, meaning the value changes steadily as time passes to form a straight gradient on a graph. And you can control interpolation between keyframes by describing an easing curve. Whether you were changing the Y coordinate of a bouncing ball, or changing the color of a rectangle in a Button template in response to a mouse click, in the first release of Blend you would have used a Storyboard to do it. Something you would have known about, too, is a handoff animation. This is an animation that has no keyframe at time 0 so that, when the Storyboard begins, property values are snapshotted and gradually changed to the value of the earliest keyframe. Handoff animations are important when defining the transition into a control state because you need the animation to be continuous even when it is interrupting an already in-flight transition (say you move the mouse over and then away from a control before the transition into the mouseover state completes).
Storyboards are available in all project types. They’re just as useful today as ever, and they are worth learning how to use, because at some point you’ll probably need to use them. They give you the most control over animation, but control can come at the cost of some effort.
For the task of customizing the look and transitions of a control’s visual states, there’s an alternative and arguably simpler mental model than using a Storyboard to define the transition into a state. The simpler mental model is that you draw the control in each of its states then, if it’s important to you, specify how long any of the transitions take. I say ‘draw’ because that’s morally what you’re doing; strictly speaking you select a state in Blend’s States panel, set properties, select another state, and so on, but you’re drafting a static image of how the control looks in each state. You needn’t be concerned with animation, although it’s interesting to note that the runtime that supports this mental model (that runtime is known as the Visual State Manager, or VSM for short) does generate a handoff animation for each state transition. For practical purposes, drawing states and setting transition durations like this gets the job done much of the time without needing to see Blend’s Timeline at all. But, if you need a steady state animation (say you want the blue focus rectangle to pulse all the time a control is focused), then yes you’ll need to open the Timeline and drop a couple of keyframes and set the animation to repeat indefinitely. Or if you want a shiny reflection to flash across a glass button during the transition from Normal to MouseOver, then again you’ll need to know what a Storyboard is.
Of course you can leverage the Visual State Manager in your own UserControls too. This is because states can apply at the level of the individual control (e.g. in the MouseOver state a Brush is a different color) as well as at the level of a page or scene (e.g. in the ShoppingCartOpen state an otherwise hidden panel is visible). So, you can add states to one of your UserControls that represents a page or scene, set different properties in different states, then use GoToStateActions to drive state changes in response to events.
The Visual State Manager is fully integrated into Blend Silverlight projects and SketchFlow Silverlight projects. You can also use VSM in WPF projects although, while the UserControl experience is the same as for Siverlight, not all WPF custom controls support VSM. I’ve written previously about the States panel and WPF controls.
The last tool I’ll mention is the SketchFlow Animation, and this tool is available in SketchFlow projects only, both WPF and Silverlight. A SketchFlow Animation is logically a ‘storyboard’ in the true sense of the word: a sequence of frames that tells a story. When you’re building a prototype, you don’t want to implement a feature fully in order to demonstrate it. Playing back a scripted example of the interaction you have in mind gets the job done at the prototyping stage. So if you want to show off how you imagine your application will reorganize and animate in response to the user dragging a product into the shopping cart, you could create a new SketchFlow animation and then draw a few frames showing how the product gets dragged between containers and how the layout of those containers responds, and even specify the easing between frames.
For those who like to know how things work under the hood, a SketchFlow Animation is represented internally as a VSM state group. But you don’t need to be familiar with VSM to use a SketchFlow Animation. Nor do you need to be aware of what a Storyboard is, nor be able to use Blend’s Timeline. In a sense, each frame (or state) in a SketchFlow Animation is a keyframe, but at a macro level so that each keyframe defines the entire scene at a point in time rather than the micro keyframes in a Storyboard that define a single property’s value at a point in time.
Now that you have an idea of what these different pieces do, and when they’re available, you’ll be able to pick the most efficient tool for each animation job you want to do.