Silverlight 2 Beta 2 has introduced a number of fixes, additions and changes to the previous Beta 1 version. As I said in a previous post, I believe the improved error handling and detailed exceptions are among the best improvements, and also the less commented.
There have also been several improvements in Expression Blend, most of them regarding the Visual State Manager (which I’ll describe in a few moments), but Scott Guthrie has already described them flawlessly.
As for a detailed list of changes, you can always refer to MSDN. What I will be focusing in here are all breaking changes that you will encounter when migrating your Beta 1 application to Beta 2, since most of them won’t be noticeable in compile time.
What you will first surely notice after updating to Beta 2 is -obviously- that your code no longer compiles. These are by far the easiests errors to fix. Most of them will be regarding namespaces, or definitions of Dependency Properties, since the signature of the Register method has changed slightly to be more like its WPF equivalent. The DialogResult enum has been replaced by a bool? as the return type of OpenFileDialog, behaviour also shared with WPF.
Fairly easy, isn’t it? Migrating a whole Silverlight application from Beta 1 to Beta 2 hasn’t taken more than a few minutes. However, when you run the application, you will realize that it isn’t that easy.
The first problem you might encounter, if you are using a Web Site Project to run your Silverlight application in an HTML page, is seeing this logo instead of your welcome screen:
This will redirect you to the Beta 1 download page, stating that the application you are trying to open has been developed in an earlier version, even though Visual Studio has already updated the project.
This just requires a correction in the HTML code of the page. Look for a line similar to this one:
<a style="text-decoration: none;"
<img style="border-style: none"
alt="Get Microsoft Silverlight" />
Now, the application finally runs. However, it is most likely that if you have been playing with control templates (and you should have, since it is there where lies most of Silverlight’s power), some things may appear broken.
Silverlight allows you to completely redefine a control’s visual tree, thus making a button render as a textbox with a calendar floating around it. It is extremely flexible, and worth a whole post in the blog.
Some controls expect certain elements in their visual tree for correct behaviour. For example, a ScrollViewer expects two ScrollBars, one vertical and one horizontal, to handle the scrolling of its contents.
Now, how do you specify inside the control template (the mechanism to override the control’s visual tree) which scrollbar is the horizontal one and which one is the vertical one? You may even have more scrollbars, just for decoration, or to handle some other content. Well, you use a specific x:Name for it. If a ScrollViewer finds a ScrollBar named HorizontalScrollBar in its template, then it assumes it is the one that handles the horizontal scrolling of its content. If the name is something else, then it is just ignored and rendered without any special considerations. After all, it is just a name.
The problem here (and we finally get back to the differences between beta 1 and beta 2) is that those reserved names have changed in beta 2. HorizontalScrollBar in beta 2 was HorizontalScrollBarElement in beta 1. This means you will have to rename most of them everywhere you have used them (luckily, the change is nothing more than removing the ending Element in most cases). And the big problem, is that Visual Studio will not warn you against this, since you are just setting a name. The only clue you will have is that controls you have templated won’t behave correctly.
Last but not least, the introduction of the Visual State Manager has also changed quite a lot of things. Let’s take as an example the check box. Clearly, you want it to render differently if it is checked or not, if it is grayed, if it has focus, if it is right under the cursor, etc. In beta 1, the way to do this was by addind Storyboards to the visual tree’s root with -again- reserved names. These are the storyboards you had to add to control all the different renderings:
<Storyboard x:Key="Normal State" />
<Storyboard x:Key="Checked State">
<Storyboard x:Key="Indeterminate State">
<Storyboard x:Key="MouseOver Unchecked State">
<Storyboard x:Key="MouseOver Checked State">
<Storyboard x:Key="MouseOver Indeterminate State">
<Storyboard x:Key="Pressed Unchecked State">
<Storyboard x:Key="Pressed Checked State">
<Storyboard x:Key="Pressed Indeterminate State">
<Storyboard x:Key="Disabled Unchecked State">
<Storyboard x:Key="Disabled Checked State">
<Storyboard x:Key="Disabled Indeterminate State">
Quite a lot of states. If you are wondering why they are storyboards (since they handle animations), it is because the specified animation is executed whenever you enter the specified state. A bit verbose, but gives you a lot of control.
Now in beta 2 the syntax has changed. Visual States are organized into orthogonal State Groups, and a control is always in one and only one state of each group. Returning to the CheckBox example:
|Normal||CommonStates||The default state.|
|MouseOver||CommonStates||The mouse pointer is positioned over the control.|
|Pressed||CommonStates||The control is pressed.|
|Disabled||CommonStates||The control is disabled.|
|Focused||FocusStates||The control has focus.|
|Unfocused||FocusStates||The control does not have focus.|
|ContentFocused||FocusStates||The content of the control has focus.|
|Checked||CheckStates||IsChecked is true.|
|Unchecked||CheckStates||IsChecked is false.|
|Indeterminate||CheckStates||IsThreeState is true and IsChecked is null.|
You can now define storyboards for both states and transitions between states of the same group. For example, you may want the MouseOver animation to be different if the control was previously Pressed or Disabled.
This means, however, that you have no control over the transitions between states of different groups, making it less verbose but less powerful at the same time. Suppose you want the checkbox to turn red if it is Disabled and Pressed. In beta 1, you just created a ColorAnimation inside the Disabled Checked State. Now, you have no communication between states of different groups, and can’t determine when both Disabled and Checked states are present.
The idea is to use different ways to identify groups. Focused is usually represented by a dashed border around the control. Checked states by drawing a check (d’oh) inside the box. And common states, such as mouse over or pressed, by changing its color or shade.
This means that there is no way to directly translate what you have done in beta 1 into beta 2 in terms of visual states. Nevertheless, it is far less verbose, and the introduction of the Visual State Manager in Expression Blend allows designers to work easily on this.
As for the syntax, note that you now need to add the System.Windows namespace to add a reference to the VisualStateManager:
And instead of keeping storyboards loosely as resources, you add them inside VisualStateGroups, which are inside the VisualStateManager, which is inside the control’s resources (yeah, everything end up as a resource).
<vsm:VisualTransition To="MouseOver" Duration="0:0:0.1" />
<vsm:VisualTransition To="Pressed" Duration="0:0:0.1" />
<vsm:VisualState x:Name="Normal" />
Keep in mind that Visual Studio won’t like the VisualStateManager.VisualStateGroups tag, but it will compile anyway and the application will run smoothly.
As a final issue to take into account, is the handling of mouse events, which has changed favourably to be more like WPF. Jesse Liberty has an excellent post explaining this change, but it sums up to the fact that the Handled property in the arguments of mouse events is taken into account when bubbling (or not) the mouse event; altough the reflector shows that the ListBoxItem never bubbles it.
To sum up, some of beta 2 breaking changes are not shown by Visual Studio after the upgrade, and they have to be searched for manually, which may be a bit annoying. Nevertheless, the huge leap between the two betas in both support, controls and stability makes it worth the effort.