Visual State Manager. Easy to understand in principle. But it takes some getting used to to be able to use it… .
There is a lot of information about VSM available, e.g. a quick introduction at silverlight.net, and when I first started to tackle VSM I read it all and then some (felt that way, anyway). Still, my first experiments with VSM failed miserably—and it did so because of a lack of understanding. Because the one main issue for me was that all the articles and screencasts explained what the VSM does and what great effects one (well, someone else) could achieve with it, yet all with the emphasis on ‚what‘ (and usually all at once), not on ‚how‘ (in small digestible chunks).
So, if you have looked into VSM and didn’t quite get it, but only just, then this post may be for you. First I‘m going to dive into some code, afterwards I’ll try to offer a few hints that should help you getting started with VSM.
The Crash Course
Controls have states (like normal, pressed, focused, for a button); states are represented by VSM as Visual States, organized in distinct State Groups. State Groups separate mutually independent Visual States (e.g. pressed state or mouse over are independent of the focus state). Silverlight allows to define these states in templates, along with State Transitions that define how the state change is to happen (e.g. instant change or some animation).
Silverlight also provides an attribute, namely TemplateVisualStateAttribute, to declare the supported Visual States and Groups on a control. Keep in mind however that this is merely for tool support and perhaps documentation. At runtime, the presence or absence of these attributes is of no consequence at all.
OK, let’s see some code. I’ll build on the image button from my last post. It should support three different images, as well as a focused rectangle. (I’ll leave out the text though. I don’t need it and it would complicate matters for this post without gain.) The button class already defines the Visual States and Groups, I’ll stick with that.
First I extended the image button control class to support three dependency properties, namely NormalImage, HooverImage, and DisabledImage. (I could have added a ClickedImage, but I‘ll solve that otherwise.) To make a long story short, here is the custom class, defining the necessary dependency properties:
The button inherits the VSM attributes from its base class, thus I don’t have to reiterate them here.
Having done that I can already use these properties to set them in XAML:
Of course it still uses only the one image, I gave it last time. So, the next step is to extend the template with images, and other parts, to accommodate the Visual Styles. If I can live with XAML, I could do this using Visual Studio 2008. To do it in a design view I need Visual Studio 2010 or Blend.
In any case, this is conventional designing, it’s not yet time to look in blend at the “States” panel in Blend! And when it comes to this, VS2010 is also out of the game (at least in beta 2).
The resulting XAML looks somewhat like that:
Note that I used a Grid to stack the images on top of each other. Note also that the default settings for all parts are compliant with my „normal“ button state, i.e. the second and third image are invisible, so is the focus rectangle.
Now that my control contains all the primitives I need, it’s time to enter VSM. To prepare for that, I manually provided the State Groups and Visual States. This ensures that I get all states (Blend would only add the ones it manipulates, and since the normal state is going to be empty, it would always be missing), and in the order I prefer.
Now is the time to enter blend, select the button, then the current template, and have a look at the “States” pane.
Note that the “States” pane contains the State Groups with their respective Visual States. Blend gets this information from the TemplateVisualStateAttribute on the class, but also includes additional states and groups it finds in the template XAML. Additionally there is a “pseudo-state” named “Base”, which is simply the “state” in which the control is without putting it in a distinct state.
Now I went ahead, selected the state in question in Blend and changed the controls to match my design. Since I had the desired design figured out before I started the VSM – up to which properties to change for a transition – this was as simple as can be. For the mouse over state:
Note how Blend shows the design area with a red border and a “recording mode” sign. Every change to the template is now recorded as state change for the selected state, mouse over in this case. (You could switch recording off by clicking on the red dot in the upper left, and manipulate the properties ordinarily; yet selecting another state will switch it back on, so this is OK for some quick fixes, but too error prone for general editing.)
Note also that the “Objects” pane shows not only the controls, but marks those affected by the currently manipulated state with a red dot and puts the manipulated properties beneath. In case you accidentally manipulated the wrong property, you should remove this entry, rather than simply change it back, otherwise the (trivial) transition will remain in the XAML.
Just setting the visibility of two images results in some verbose and (at first sight) rather confusing XAML:
The disabled state looks similar. The click state is represented by the hover image which is moved slightly off center to achieve the click effect (“Properties” pane, “Transform”).
And here’s the resulting button in action, showing normal, hover, disabled, and clicked state:
What I just presented was a fast forward replay of employing the VSM. Using VSM minimalistic to the extreme actually, since I have left out quite a bit of VSM functionality, most notably transitions with animations. Still, I have applied some guidelines I learned to value when using VSM, that I’d like to point out.
So, here are some of the twists that made VSM useful to (rather by) me… (some learned the hard way).
:idea: Hint 0 (The most general hint): States need careful planning.
If you don’t know yet what the control should look like in the various states, you should shy away from the “States” pane in Blend. Start with conventionally designing the control, It may even help to design a separate control template per state, and merge them only after the design has reached a stable state.
:idea: Hint 1: Don’t look at existing controls.
It’s tempting to look at the existing templates, with Blend the XAML is only a mouse click away. Don’t. The button template has ~100 LOC, and I’ve seen others with more than 300 LOC. And what’s more, they are fully styled, meaning that they employed probably all the features, caring for sophisticated visual effects but not exactly for the poor developer trying to deduce the workings from looking at the XAML.
:idea: Hint 2: Start simple.
Many samples quickly jump at animations used for transitions, easing functions, and slicing French Fries. For me one key to understanding VSM was to stick to the minimum at first. States. Transitions only as simple as possible. Period.
:idea: Hint 3: VSM is not about creating states. It is about styling them.
My initial thinking was „I have a button with a normal image; in disabled mode I need to have a disabled image…“. This led to all kinds of mind twists, like „how do I create an image control during a state change?“ „Should I rather replace the image URL of the existing control, and how?“, and others. It was a crucial part of understanding when I realized that I do not have a button with one image in one state and another image in another state. What I have is a button with three images in all states, as presented above. The difference between the states is merely which of these images is visible and which is not.
:idea: Hint 4: When designing a new control, avoid the VSM “States” pane for quite some time.
There is one pitfall I managed to hit several times in the beginning. I started Blend, selected the particular state I‘m interested in, and tried to design my control for that state. This is futile, because Blend does not actually design the control (as in setting property values), rather it designs the transitions to these values. (You could switch off recoding mode, but Blend really insists on switching it on again and again and again.)
Therefore I generally design my control „conventionally“. I.e. I place the normal image in a grid and style it; then I make it invisible (kind of a manual state change) and do the same with the next image; and so forth for all states. Only when I‘m done with this I allow myself to even look at the VSM support in Blend.
:idea: Hint 5: The visual state for the normal state is always there. And always empty.
Worse, you’ll have to include it manually in XAML, since Blend doesn’t put it there… :-(
„Normal state“ is the default state of the state group. Each state group has one; it doesn’t have be be named „normal“, but it has to exist. This is the state in which the control is by default, after initially displaying the control, and before VSM has even touched it. The one that is denoted as “Base” in the “States” pane.
The „normal“ state has to be declared, because otherwise the control will not be drawn correctly after it has been in a different state, say normal –> hover –> normal. And it has to be empty because otherwise the control would show up in an undefined state, at least according to VSM, which can never again be reached, once the control was in a different state. This would lead to all kinds of inconsistencies.
Lemma: All controls in the template initially have property values compliant with the normal state. In the image button example: The normal image is visible, the other images invisible.
:idea: Hint 6: VSM is not about designing states. It’s about designing differences between the state in question and the normal state.
Suppose I have the control designed the „conventional“ way with the looks of the normal state; I also have yet invisible controls for the other states. Now is the time to enter Blend and the “State” pane. Choose the state in question, e.g. mouse over, and manipulate exactly those properties that constitute the difference between normal state and mouse over state. I.e. set the normal image to invisible and the hover image to visible. Blend will record the respective transitions.
It’s always this difference, always normal state vs. the state in question. Only if you achieved the first belt in using VSM and signed the no-liability warrant should you go ahead and attack transitions between specific states, for complexity will explode.
:idea: Hint 7: State groups are mutually independent. And the same is mandatory for the state differences.
Never let different state groups manipulate the same properties. For example the button addresses common states and focus states independently. It would not work to implement the focused state by setting the hover image visible, as this would collide with the mouse over state and eventually result in undefined behavior. The focused state could show a focus rectangle. Or it could actually even manipulate the hover image, as long as it is not the visibility property used by the mouse over. (Whether that makes is a different question, though.)
:idea: Hint 8: Visual states are not put in stone.
Controls usually have visual states defined via attributes. However this is just some information, used by some tools (such as Blend), but of no consequence otherwise. VisualStateManager.GoToState is what triggers a transition, and it may or may not be called from the control itself. The visual states and groups defined in the template are merely backing information used at runtime. Should the need arise, I could define a new state group, say „Age“, with two visual states „YoungAge“ and „OldAge“ in XAML. Then I could go ahead and call the VSM from the code behind file of my page class to change the state. And after 5 minutes of inactivity my button could grow a beard.
So far the hints. But what about more complex demands? I have barely touched the eye catching features at all.
In my opinion, what I just presented will cover the first steps and provide a sound understanding of the core VSM principles. Once this level of understanding VSM is mastered, one can go ahead and explore other areas.
And there certainly are “other areas”. I already mentioned state specific transitions; animated transitions are another topic. If you need an example of what’s possible have a look at this online sample. This is VSM in action, admittedly complemented with some code, but surprisingly little. (You can dig into it starting Blend and opening the sample project „ColorSwatchSL“.)
Some other useful links:
And from now on it’s no longer a lack of understanding that keeps me from doing things. It’s my incompetence as designer… ;-)
That’s all for now folks,