« Palmerston North .NET User Group - Introduction to WPF | Main | Wellington .NET User Group - Introduction to DSL Tools »
June 11, 2008
Why the Silverlight VisualStateManager is wrong
Silverlight has a control templating system similar to that of Windows Presentation Foundation. However, Silverlight and WPF take different approaches to updating the user interface as the user interacts with it. WPF uses triggers: the creator of a template specifies changes to the template to be applied under certain conditions. Silverlight instead has the Visual State Manager: the creator of the control puts it into different visual states, and the creator of the template applies UI effects according to the visual state.
The difference is clearer with an example. Consider how we would make a button become highlighted the mouse is over the button. For example, the Windows XP Start button glows when the mouse is over it; normal dialog buttons display a yellow border. In WPF, we would achieve this effect in the button template with a Trigger on the IsMouseOver property. In Silverlight, we would handle the MouseEnter event in the control code by setting the button's visual state to "Hot", and then in our template by including a VisualStateManager segment specifying how to handle the "Hot" state. (I'm simplifying a bit here. Ian Griffiths has a great explanation.)
There's been some thoughtful back and forth about these different approaches, and the rumour is that WPF will be incorporating the Silverlight approach. Let's hope not. Although the Silverlight approach has some attractive features, it fundamentally breaks the lookless model of WPF. It forces a control to have brittle knowledge of its user interface. It takes the so-called "parts and states pattern," which is not so much a pattern as an admission of failure, and makes it the only game in town.
That's not to say that the Silverlight approach doesn't have its good points. The ability to orthogonally decompose visual state into its components, and to encode once and for all when a button should be hot and when it shouldn't, is attractive. At present, a WPF template author needs to consider all the possible conditions that should cause a button to display as hot. For a more complex control with a more complex visual model, that invites bugs. The "parts and states" model adopted by Silverlight, it is argued, makes the control's visual contract more explicit. Here is a list of the visual parts and the visual states, says the control: you decide how you want them represented, and I will look after the rest.
The problem with the Silverlight approach is that it requires the control author to anticipate the possible user interfaces that designers might come up with. Let us suppose, for example, that the author of the Button code, being a developer, hadn't really noticed that user interaction had moved on since Windows 3.x, and declared only two visual states, "Normal" and "Pressed." A Silverlight designer who wanted their buttons to respond like XP or Vista buttons would be out of luck. There is no way for the Silverlight template to represent "hotness," because the concept doesn't even exist. By contrast, a WPF designer could create their own visual states as they saw fit.
This is not just about the subtleties of graphic design, or the joys of a full-on developer-designer workflow. The ability to trigger off any property is fundamental to visualising data with WPF. Consider a custom text box for editing numeric values: the sort of thing you'd be using in a line of business application, a "GUI green screen" with none of your beret-wearing designers involved. You might need to display negative values in bold, red text so your users can easily identify deadbeats and go remonstrate with them. No problem: add a trigger for the Value property. (You'll need a value converter to translate a value into a sign, but you can still create that without having to modify the underlying control.) In Silverlight, you'd have to petition the control author (who might be a third-party vendor) to add a "NegativeValue" visual state. And then next day you'd find that you also needed a "getting low" state so your users could ring people up and advise them to top up their account quick...
The Silverlight VisualStateManager model, quite simply, cuts off the ability to create even the most rudimentary adaptive data visualisations. As in the Windows Forms era, every view option requires support in the control itself. Users of a control can no longer choose their own criteria for changing the display.
What about the control contract argument? A WPF control can easily expose a suggested contract if the developer has one in mind. Again, consider the button example. If the Button developer wants to give the template author a shortcut, he can create an ActivationStatus property of enum type with possible values Normal and Pressed. A designer who is building a Windows 3.x retro theme can stick to using those properties. A designer who wants pulsing glows and mellow floating clouds, and finds that the ActivationStatus property doesn't meet his needs, can ignore it and go straight for the mouse events. (The Mindscape NumericTextBox does something like this, by offering a NegativeStyle property for the common case, and a triggerable Value property for custom cases. Not quite the same, but you get the idea.) The Silverlight VisualStateManager does have the advantage that controls are required to declare their visual states through attributes, which makes it easier for tools such as Blend to tell designers what states they need to handle; but this could easily be added to WPF by defining a property-level attribute. For example, our Button developer could place a hypothetical [VisualState("Activation")] attribute on the ActivationStatus property.
It has to be said that, given the constraints of Silverlight, the parts and states model, and therefore the Visual State Manager, does make some sense. Silverlight's data binding is much weaker than WPF's; therefore Silverlight control developers are much more dependent on writing procedural code and calling setters on their template elements. (In WPF you would normally prefer a TemplateBinding; that is, the template element reflects information of interest from the control's lookless model, rather than the control code pushing that information to distinguished elements known to it at design time.) In order to call a setter, you need to know what your template elements are and have a way to locate them, and that drives you towards the parts model. The parts model drives you towards assumptions about how your control's UI will be made up. And if you are making assumptions about how your control's UI will be made up, then you can probably make some corresponding assumptions about how your control's UI will behave. In which case you might as well code up those assumptions and spare the template author the hassle of writing <Trigger Property="IsMouseOver" Value="True"> for the eight millionth time. It is indeed an exercise in the art of subsetting.
However, it's important to realise that the ultimate justification for the VisualStateManager lies in covering for present weaknesses of Silverlight. In the WPF environment, where we already have template triggers and powerful data binding, VisualStateManager would be a misguided step towards a closer coupling of controls and templates. The effort required to add VisualStateManager to WPF would be better placed adding triggers and data binding to Silverlight, and I hope that's what Microsoft does.
June 11, 2008 in Software | Permalink
TrackBack
TrackBack URL for this entry:
https://www.typepad.com/services/trackback/6a00d8341c5c9b53ef00e5534abc1d8833
Listed below are links to weblogs that reference Why the Silverlight VisualStateManager is wrong:
Comments
Excellent! Down with the VisualStateManager!
Posted by: Rick Boykin at Jun 12, 2008 9:43:53 AM
Your lament (a common one and understandable) is the lack of Triggers in Silverlight. VisualStateManager is compatible with Triggers as I mention here: http://blogs.msdn.com/johngossman/archive/2008/06/10/visualstatemanager.aspx
So I maintain VSM is a step forward for SL and WPF...and unfortunately the work to do Triggers in SL was independent and much greater, so we couldn't not do VSM and use those resources on Triggers.
We are very aware of the pain caused by lack of Triggers and the problem will be addressed.
Posted by: John Gossman at Jun 14, 2008 3:24:15 AM
Thanks for stopping by, John. I saw that article of yours the day after I wrote this one and meant to post an update, because the approach you describe (of allowing the template author to define visual states) largely mitigates my concerns, and provides the best of both worlds -- templaters will be able to write control visuals against high-level abstractions of visual state, *and* will be able to specify their own sets of visual states (which addresses the "unanticipated requirement" issue). Good stuff.
Posted by: Ivan at Jun 14, 2008 8:32:02 AM
Working a lot with designers, I'd like to offer a slightly different perspective on this debate. Disclaimer: I work on Expression Blend and have been intimately involved in the VSM design.
VSM has been introduced because the WPF model, for all its power and flexibility, also requires the creator of a control template to have very deep understanding of the properties and property changes coming from the control: The wiring-up between control functionality and control visuals is *always* provided by the template. It is not an opt-in model, making even the common simple cases of control re-styling fairly complex, as it is not trivial to modify or replace the visual tree without breaking functionality.
Also, creating robust transitions between different control states is quite difficult to do well in the WPF model (as there is neither an explicit model of states nor of state transitions), and transitions are increasingly important for good design.
Finally, it is much harder to use the WPF model in other contexts, such as user controls, that also need to manage visual states.
I believe that creating control skins really should be a task accessible to visual designers, and that is a difficult proposition if you have to learn all the concepts necessary to understand the trigger model even for simple tasks of visual refinement. Asking so much from designers from the start is not an ideal on-boarding strategy, and I think this is even more true for web applications with a broader audience of creators than you would find in WPF ISV scenarios.
In short, the original WPF model optimizes for sophisticated control re-styling (and, in my opinion, does not give enough weight to transitions), at the cost of making simple skinning relatively difficult. The design goal for VSM was to give the lower end of the task spectrum greater weight, while still providing a less steep ramp to more sophisticated customizations.
With VSM, the default direction of wiring up templates and controls is inverted: The core functionality is made available by the control, and the template just needs to provide appropriate visuals within a set of states. This approach makes it possible to automatically generate flexible transitions between states, and allows designers to (largely) focus on the visual design, with much less exposure to other concepts.
You are right that VSM as available in the current version of SL lacks the ability for designers to go beyond the set of states expected in the original design of a control.
I also agree that this is an ability we need to provide. However, I believe there is no design issue within VSM preventing this from happening - in fact, you can see some of the necessary features in the case of UserControls, where you can create states and state groups on the fly, to build a stateful component.
As John writes "We are very aware of the pain caused by lack of Triggers and the problem will be addressed."
I believe that VSM is a design capable of giving users a good solution on both ends of the spectrum of control skinning: An easy to learn entry point, accessible for visual designers, for quick replacement of visuals and transitions, as well as richly customized states for those who want to opt-in into more complex techniques to extend the original design intent of a control. Not all pieces are in place for this in the current SL version (and within the tool support in Blend), but stay tuned.
Posted by: Christian Schormann at Mar 1, 2009 4:01:24 PM
Hello Christian,
Thanks for the detailed and thoughtful comments: it's great to have a perspective from the designer side of things. I think you have hit the nail on the head when you say, "the original WPF model optimizes for sophisticated control re-styling... at the cost of making simple skinning relatively difficult." In particular, in WPF, designers need to have a very close understanding of the UI interaction model. They have to make sure they have captured all the low-level physical conditions under which a button should be considered "hot," what possible transitions there are from those states, etc. What's *right* with the Silverlight VSM (and now the WPF VSM) is that it provides an abstract interaction model for designers to work against. As you say, that's quicker for them to get started with, and it covers the 90% case.
The cost in Silverlight has been the lack of escape hatch. You can provide abstraction capability like the VSM in user code over an unabstracted model like WPF's. You can't get the raw model back from the abstracted model: you're stuck with the abstraction. It would have been great if Silverlight had gone the WPF route of triggers in the box, and VSM shipped as an out-of-band update like the new controls. But your comment about rapid on-boarding makes sense, and was something I hadn't really appreciated before: given the state of the RIA market, Silverlight 2 needed to win over Web designers very quickly, and waiting for an out-of-band update would have had a major impact on that.
Fortunately, we're now beginning to see the best of both worlds. WPF is shipping a VSM via the Toolkit, which means there is a convenient, designer-friendly abstract interaction model which will serve in many cases, and the option to drop down to triggers when a more radical styling is required. From the hints that people like you and John are dropping, it sounds like Silverlight is going to acquire triggers or dynamic states or some other escape hatch to support "unanticipated" styling. This is going to be great for both platforms.
Once again, thanks for taking the time to provide the additional perspective!
Posted by: Ivan at Mar 1, 2009 4:41:49 PM