Here we are – the final post of our Parts & States Model series for Silverlight 2 controls. Hope you’ve enjoyed the ride so far!
Today, we’ll go through some general recommendations on how to use the Parts & States model. We’ll also take a look ahead: VisualStateManager on Windows Presentation Foundation and future releases of Silverlight.
(Series Link: Part 1, Part 2, Part 3, Part 4)
Parts & States Model Recommendations
1. Use the Parts & States Model with Custom Controls and UserControls
Like we mentioned in the first post, the Parts & States Model is just a pattern. It is not required by the runtime, and it’s perfectly fine to build controls without the Parts & States Model and VisualStateManager.
However, we do think this is a good model. And Blend will only be able to support skinning of custom controls using the Parts & States Model.
And while this series concentrated on VSM with Custom Controls, remember you can use it with UserControls as well!
2. Custom VSM xmlns
This one is less of a recommendation and more of a heads up.
Because of a known Silverlight 2 Beta 2 bug, you need to use a custom xmlns for VisualStateManager and its related classes.
1: xmlns:vsm=“clr-namespace:System.Windows;assembly=System.Windows”
For consistency across controls, we recommend the following naming convention.
4. CommonStates and FocusStates are special
Many controls define these two state groups:
If your control is going to have some or all of these states, for consistency, we recommend the above grouping and naming.
5. Be resilient to missing Parts & States in template
There are many reasons why a particular ControlTemplate might not supply a given part or state: the designer may have deliberately chosen to leave it out. He/she might not have created it yet. And so on.
It is good practice to prevent crashes or other catastrophic failures when a part is missing.
Note: The VisualStateManager.GoToState() method already takes care of this for states – it returns false when the target VisualState is not found.
6. Consider supporting “fallback” states
For complex controls, it is sometimes interesting to provide a fallback mechanism for particular states that do not exist.
1: if (VisualStateManager.GoToState(this, “FocusContent”, useTransitions) == false)
2: {
3: VisualStateManager.GoToState(this, “Focus", useTransitions);
4: }
The advantage of this approach are pretty intuitive: the control continues to visually function correctly when a designer hasn’t provided a particular state.
But there are also some significant negatives: the fallback states mechanism isn’t fully integrated into the Parts & States model, which means that Blend has no way of knowing about them.
So, please use fallback states sparingly and only when the control is sufficiently complex enough to warrants it.
Also, if you think this is a pattern that you’ll leverage often, let us know! We’d love the feedback.
7. Subclasses should only add states in new state groups (not existing state groups)
As you know, each state group is orthogonal. This makes it easy for a subclass to add new state groups. For instance, you can create a StackButton that derives from Button and adds a StackStates group:
This works because the StackStates state group logic is completely independent from the Button’s logic around CommonStates & FocusStates.
However, if you want to add a new state to an existing state group, the state group logic can become jumbled. It’s is difficult to guarantee that the right logical state checks will happen in the right order.
Let’s make this clearer with an example. BasicControl defines two states in its CommonStates: Normal, MouseOver. Its logical state machine is:
- if (mouse is not over control) goto Normal
- if (mouse is over control) goto MouseOver
Now, ExtendedControl derives from BasicControls and wants to add a Pressed state. The goal logical state machine would be:
- if (mouse is not over control) goto Normal
- if (mouse is over control AND mouse button is not down) goto MouseOver
- if (mouse button is down) goto Pressed
However, there is no good for way for ExtendedControl to add the (AND mouse button is not down) check for the MouseOver state, since that logic lives in the Button base class.
All this just means: Subclasses can always add new states to an new state group. But we recommend against adding new states to existing state groups.
Note: There are different ways (each with its own pluses & minuses) for the platform to address this limitation in a future version. We’re currently leaning towards a Triggers-based solution (yes, I said triggers). For more, keep reading.
Looking Ahead
VSM & Windows Presentation Foundation
Silverlight’s Parts & States Model leverages many features (like ControlTemplates, GetTemplateChild() helpers, etc) that already exist in Windows Presentation Foundation.
However, there are some features – namely VisualStateManager and its associated classes – that do not yet exist in WPF. The good news is that the next version of Windows Presentation Foundation will include VisualStateManager!
For some that are trying to move their Siverlight 2 controls & skins to WPF now, the next version of the .NET framework may feel a ways off. To help remedy that, we are currently looking into shipping a WPF assembly that contains VisualStateManager before the next full release of WPF. Plans are still early – and so the timeline & ship vehicle details are still being worked out.
More details as we have them!
Future Silverlight Features
One of the often asked questions about the Silverlight control model is: “Where are the Triggers?” In fact, it’s normally, “Where are the TRIGGERS?????” 🙂
There are a lot of different reasons why we were not able to bring Triggers into the Silverlight 2 release. The primary technical challenge was that our property system architecture is not sufficiently complex to support them. This will however change in a future version of Silverlight, and then we’ll be able to start supporting Triggers.
How would Triggers & VSM play together? The tentative design brainstorm looks something like:
1: <PropertyTrigger Property="IsPressed" Value="True">
2: <GoToState State="Pressed"/>
3: </PropertyTrigger>
The platform would provide a GoToState trigger action that causes VisualStateManager to initiate a state change to the desired state.
The designer would, then, have the option of using the built-in states that come with the control (and leaving the visual state change logic to the control). OR, he/she can take over and trigger all the VSM state changes from XAML. In the latter case, it would also be possible for the designer to add states to new or existing state groups that a control code does not know about.
Exciting stuff coming!
The End
So that’s the end of our 4 part series on the Silverlight 2 Parts & States Model. If you have questions or feedback, we’d love to hear it.
If this series has wet your appetite for VisualStateManager, here are some more great resources:
- Christian Schormann‘s Blog (Group Program Manager for Expression Blend)
- Steve White’s video tutorials (Program Manager for Expression Blend)
- Celso Gomes’s tutorials (Designer for Expression Blend)
- Tim Heuer‘s Blog (Senior Program Manager on the .NET Developer Platform)
- Jesse Liberty‘s tutorials (Senior Program Manager on the .NET Developer Platform)
- Scott Guthrie‘s Blog (Corporate Vice President of the Developer Division)
Triggers?! Yes Yes Yes! 😀
the second choice: the designer can add new states 😀
Great series, thanks 🙂
Excellent series. You mentioned that the Parts & States Model could also be used with User Controls. I’m having trouble conceptualizing that, but I guess you would just leave the XAML of the UserControl relatively empty, then access the ControlTemplate from the UserControl’s resources (or the Application.Resources). It would be good to know why you’d want to do all this for a UserControl, instead of just declaring the UI in it’s XAML. Maybe for UserControls, you build your Parts into the XAML while keeping your Visual States and Transitions separate elsewhere? Wondering…
The major problem with the current GoToState is that it is fully encapsulated in the ancestor class. Adding a new state to a state group requires breaking encapsulation, or rather unencapsulating things that were given too fine-grained encapsulation… triggers are a good idea and I like how the overall architecture of WPF is selectively open and exposes states through statechart-like analysis patterns.
It was an excellent series, well written, and very informative (at least to me).
But I am still left with a question.
It seems to me that the example could have been accomplished much easer with templating a UserControl. I think I could easily capture hover, disable, and mouse events and use the VSM in blend to rapdily create the same effects.
I must be missing something. Why would I go to the work of building the custom control from scratch. It seems there is something I am still not understanding where method gives some power I would not mormally have.
Wow! Exactly what I was looking for! Most of tutorials use Blend (not that is bad, but I understand better with source code).
Thanks for a great set of posts.
Just a comment on the future trigger support. Please consider adding a UseTransitions property as well, similar to your GotoState method:
Looks like your comment area doesn’t like XML input, but I was trying to enter:
< GoToState State=”Pressed” UseTransitions=”false” / >
This sample no longer seems to work with the Silverlight 2 Release Candidate. The GoToState(bool useTransitions) helper method now throws an InvalidOperationException – Element is already the child of another element.
Will you be posting an update on how to get this to work with RC0?
I found a work around. The storyboard for each individual VisualState must be declared within the VisualState explicitly, not as a reference to a resource.
This series proves you have a great talent for teaching. It helped me a lot. Thank you!
Pingback:Louis Vuitton Pacific Series 2009 Auckland New Zealand – The Silverlight Story - Nigel Parker's Outside Line - Site Home - MSDN Blogs