Silverlight: the art of subsetting
I am an architect of WPF, both the full desktop version and the subset that provides the UI framework for Silverlight. This subsetting exercise raises challenges I've not run into before when designing software. Simply put, how do we keep the framework small without completely changing the programming model? Keeping it small is relatively easy: just take out classes and APIs. You of course lose functionality in the process, but almost always when designing software you start out with many features and then must prune back in order to ship. Subsetting also makes it hard for users to move substantial bodies of code from the big system to the small system. Not only features, but individual APIs that we decided to cut "because they weren't critical" are naturally called all the time in the application code, and there is no replacement. Worse, it is easy to get confused reading books about desktop .NET or looking at blog articles about XAML and not be able to tell what is in Silverlight and what isn't. There was a simple question in the Silverlight forums this morning about how to set the Name of a Framework element. The user had seen code that simply said fe.Name="foo" and it wasn't working for him. Well, that code works on desktop WPF and it is highly unlikely the place he saw the example noted that this wasn't available in Silverlight.
To keep somewhat sane, we choose to design around making it possible to port code *from* Silverlight *to* the desktop. As long as the Silverlight APIs are a subset (with expected differences for application model) of the desktop ones, code should all just compile and run when moved over. But this is where it gets trickier than we originally imagined.
With the full desktop frameworks there are usually several ways of doing the same thing. In Silverlight we eliminate many of these variations in the search for the smallest possible code and surface area. However, what happens when we eliminate a path that is a best practice for a particular scenario? For example, there are a number of complex APIs in desktop WPF that are only used if you want the best possible performance...usually with some tradeoff in flexibility. The System.Windows.Media.Drawing class and its descendents are examples. These allow you draw shapes into a single visual and render more efficiently. Not strictly necessary, but they make for much better performance in some scenarios. These scenarios are still possible in Silverlight, but if you now port your code to desktop, you will be well served to rewrite a big chunk of code.
The above example is a bit of a special case, and I don't feel bad about it at all. A much greater struggle that hits a very large number of users is how we do Control templating. All of the APIs we use in Silverlight's Beta1 control templating model exist in desktop WPF, and yet the templates are completely different. By subsetting the APIs we ended up changing not just the best practices, but the essential model.
Let me be clear. If you write your own custom control in Silverlight, using the Silverlight model, you can create a template for it and take your custom control and its template and run them on desktop WPF. The problem is, we do not provide Triggers in Silverlight and many of the properties (IsMouseOver, IsPressed) that Triggers depend on to work. There are technical reasons Triggers were hard to add in Silverlight 2 (though we will add them in the future), but even greater was the test and development cost of adding all the additional properties necessary to make them work. So, we decided to make the controls have to "trigger" the state changes themselves in code. All this code works on desktop WPF. But existing controls, written for the desktop, don't contain the code to "trigger" the state changes, so the control templates don't do anything when applied (they create their children, but don't react to events).
I should add at this point, that we also think there are some advantages for designers and tools of the Silverlight templating model. The Parts and States model (which is just a pattern using existing APIs) adds structure to a template that makes it easier to understand. And in the future, when we add Triggers into Silverlight they are completely compatible with the Parts and States model...providing the best of the two models. Finally, the Beta1 Parts and States model is going to be considerably enhanced in the near future in ways that really show off the advantages and simplify the coding.
Sorry for the tease about future stuff (watch this space), but this posting is about the essential subsetting problem, and the control templating model has been our greatest struggle in this area. I hope this helps provide insights into the Silverlight programming model and some of the decisions we've made, which may seem arbitrary and patternless otherwise.