Styling and Skinning Your Objects
This tutorial will demonstrate how you can modify the appearance of controls in your application. There are numerous ways to do this, and various tools to do it with; I will attempt to cut through the noise and focus in on the three most common use cases:
- Use the controls as they are, modifying their appearance slightly by setting styles "in line" within the XAML (or through the properties window in Visual Studio or Blend)
- Create re-usable Style objects to enable a uniform appearance for controls that serve the same function (e.g. all prompts look alike)
- Create templates to "re-skin" controls - radically changing their appearance while maintaining their behavior.
Setting Styles In-Line
The simplest and perhaps the most common way to set an incidental style is to do so in the Xaml, either in Visual Studio 2008 (directly in the markup) or in Blend (using the properties tab).
To zero in on the issues that arise, we'll start with the application we created in Tutorial 2 - Data Binding, which you can download here.
Opening the project in Blend and take a look at the controls; you'll see a a grid with two columns and six rows. The left hand side has five TextBlocks and a button; the right hand side two TextBlocks, a ListBox, a CheckBox, and a TextBox. Open the same project in Visual Studio and take a look at the markup; the controls are unadorned (other than alignment) as shown in Figure 6-1

Figure 6-1. Project in Blend and Visual Studio (Click to view full-size image)
I've circled TitlePrompt in Blend (Objects and Timeline and Properties) to show that few properties have been set. This is confirmed in the Xaml shown in Visual Studio 2008.
You might decide that you'd like all your prompts to use a different font; say Comic Sans MS at a font-size of 24. You can do this directly in the markup in either Blend or Visual Studio, but for this tutorial (and in real life) I will edit Xaml and Code in Visual Studio, and I'll use Blend for editing directly on the design surface and through the properties windows.
To edit the Xaml by hand, simply begin typing in the values you want; Intellisense will spring to action to help you get the syntax right, as shown in Figure 6-2

Figure 6-2. Setting Font Size Style in Xaml
The result is immediately visible in Visual Studio's design window as shown in Figure 6-3

Figure 6-3. Adding Styles to the Xaml by Hand
Setting Styles as Properties in Blend
As an alternative to setting the styles in the Xaml in Visual Studio 2008 try saving the file and switching to Blend. After saying "Yes" to the prompt that tells you the project was updated, click on AuthorPrompt in the Objects and Timeline tab and then open the properties tab and from there the Text tab and set the font to Comic Sans MS and the font size to 24. Once again, the change is instant as shown in Figure 6-4

Figure 6-4. Setting Styles as Properties in Blend (Click to view full-size image)
As you would expect, the Xaml is updated as well, as you can see in the split or Xaml view in Blend or back in Visual Studio 2008,
<TextBlock x:Name="AuthorPrompt" Text="Author: "
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Grid.Row="1" Grid.Column="0"
FontFamily="Comic Sans MS"
FontSize="24" />
Setting Styles as Resources
It may well turn out that you would like all your prompts to be Comic Sans MS, font size 24, and for them to be horizontally aligned to the right (but set back from the right margin by 10) aligned on the bottom and set to the color blue.
It can get quite tedious setting all these by hand, but it is easy to create a Style Resource that you may name, and then apply to each of the controls. This allows you to create a uniform look and feel and provides a single place to change the appearance of all the prompts at once.
Resetting Properties
The first thing to do is to remove all the styling from the prompt controls. Re-open the project in Blend and control-click on the five prompt controls in Objects and Timelines so that they are all highlighted. Notice in the Properties window that the Horizontal and Vertical Alignments have a small white dot to their extreme right. That indicates that these values are set. Click on the dot and a menu will appear allowing you to reset these properties, as shown in Figure 6-5

Figure 6-5. Resetting properties (Click to view full-size image)
Once all the little white dots (other than column and row) are removed, click on each prompt individually to reset any individual properties (if you've been following along, only TitlePrompt and AuthorPrompt will have their Text properties to reset).
Take a quick look at the Xaml; the TextBlocks for the prompts now have only their Text, and their position in the grid,
<TextBlock x:Name="TitlePrompt" Text="Title: "
Grid.Row="0" Grid.Column="0"/>
<TextBlock x:Name="AuthorPrompt" Text="Author: "
Grid.Row="1" Grid.Column="0" />
<TextBlock x:Name="ChapterPrompt" Text="Chapters: "
Grid.Row="2" Grid.Column="0" />
<TextBlock x:Name="MultipleAuthorPrompt"
Text="Multiple authors?: "
Grid.Row="3" Grid.Column="0" />
<TextBlock x:Name="QOHPrompt"
Text="Quantity On Hand: "
Grid.Row="4" Grid.Column="0" />
Creating a Style Resource
Let's create a style that can be applied to all these prompts. Begin in Blend by choosing Object → Edit Style → Create Empty...
This will bring up the Create Style dialog box. You may choose to place your style in the current Xaml document, but this limits the scope of your style to this particular document. It is typically preferable to place your new Style resource in App.xaml making it available to your entire application. You do this by choosing the Application radio button. Give your style a name (Prompt) as shown in Figure 6-6

Figure 6-6. Create Prompt Style for the Application
Notice the breadcrumbs that appear at the top of the design window, shown in Figure 6-7

Figure 6-7. Bread Crumbs
Clicking on the left bread crumb, AuthorPrompt will bring you back to normal design mode. Clicking on the second will bring you back to creating your style. Make sure you have the Properties window open and start setting the properties for your style. You may want to be in "split" mode so that you can see the effect in App.xaml.

Figure 6-8. Setting a Style's Properties
Figure 6-8 shows the properties window, and the little white dots indicate the properties I've set for our Prompt style, while Example 6-1 shows the Xaml generated in App.xaml.
Example 6-1. The Prompt Style
<Application.Resources>
<Style x:Key="Prompt" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="24"/>
<Setter Property="Foreground" Value="#FF0000FF"/>
</Style>
</Application.Resources>
You are of course equally free to write the Style by hand, though for complex styles it is far easier to let Blend create it for you.
Applying the Style
To apply this style to all of the prompts, Blend offers two approaches.
The first way to apply the style is to click on a TextBlock you want to apply the style to (e.g., TitlePrompt) in the Objects and Timeline tab and then click on the menu choice Object → Edit Style → Apply Resources → Prompt.
Hey presto! The style is applied and you can see that both in the story board and in the Xaml as shown in Figure 6-9

Figure 6-9. Applying the Style (Click to view full-size image)
An alternative is to drag the Style from the resources tab right onto the control itself, causing a dialog to open asking what you want to associate the style with, as shown in Figure 6-10

Figure 6-10. Dragging the prompt into place (Click to view full-size image)
As soon as you click on "Style" the Prompt style is applied to the control you've dragged it onto!
When all the styles have been applied, you'll have to adjust the size of the control to allow for the larger prompt, but you can now have a uniform style applied to all your prompts, and if you decide you want to change them all from blue to black, you can do so by changing the resource, rather than changing each control individually.
Templates & Skinning
Sometimes you want to go well beyond styles. and totally re-skin a control; giving it an entirely different "look" without changing its behavior. That is where Silverlight Templates, the Visual State Manager and the Parts and State Model all come into play.
This is a perfect example of "hard to explain, easy to do" so hang in there.
A simple but highly effective way to locate an object is by triangulation; that is, to view the object from two or more viewpoints. By analogy, I find that when learning something new and initially confusing, it can be helpful to have more than one viewpoint on the subject. The best tutorial I've seen on this subject is by Karen Corby (should I say, "of course?" ).
The Parts and State Model
Silverlight makes a couple radical changes from the technologies we've all grown up with (ASP.NET, WinForms, etc.). In the older technologies, each "control" had a specific appearance, and as developers we had a certain amount of freedom in altering that look using some form of "styling" or, later, "skinning."
In Silverlight, every control that Microsoft supplies (and we recommend this model for custom controls, a topic to be discussed in detail in an upcoming tutorial) supports the new Parts and States Model that calls for a strict separation between the logic of the control and its appearance.
The advantage of decoupling logic from appearance is that a developer is free to change appearance and behavior separately, providing great freedom, especially when working with professional designers.
The appearance is encapsulated in a template, using the Parts and State Model and is regulated by the Visual State Manager (VSM). The icing on the cake is that Expression Blend knows how to read and create Parts and States, making skinning of controls an almost trivial exercise... well, once you know how it is done.
The Parts and State Model is built on these key concepts:
- Parts
- States and State Groups
- Transitions
Parts
A part is a named element within a control. This becomes more important when you are create templates for custom controls and we'll return to it in a future tutorial.
State and State Group
Each control has a number of "States" - determined by the designer of the control. As shown in Figure 6-11 the button has four "Common States"
- Normal
- MouseOver
- Pressed
- Disabled
It also has two "Focus States"
Notice also that the latter two states are separated into their own "State Group" from the former four. The idea of state groups is to create orthogonal groupings to reduce the potential for a combinatorial explosion of states (e.g., by using state groups, you potentially reduce the number of different states from 64 to twelve by dividing mixed states into three groups of four)

Figure 6-11. Button States and State Groups
Transitions
As it turns out, Figure 6-11 is a cheat; I cut out the "transition" timing markers to simplify the image, which originally looked more like Figure 6-12

Figure 6-12. States with Timing Values
These small numbers that I've now circled are transition timing values (measured in seconds). They dictate how long it will take to transition from one state to another.
The two that are circled in red are the defaults for the two state groups, while the two that are circled in white are overrides for specific transitions.
If you look closely at the first, you'll see on the far left the image of a star with an arrow pointing to the MouseOver state, indicating that this timing of 0.2 seconds is for transitioning from any state to MouseOver, and in the second case, 0.1 seconds is the transition time for transitioning from any state to Pressed.
What happens during that transition is determined in the Transition itself, which is in fact a storyboard (the building block of animations), and will be described below.
The key idea of transitions is to avoid snapping from one state to another, but rather to have a smooth change between states, perhaps with an interim, if fleeting appearance that eases the transition between (for example) the normal and the pressed state.
Again, by examining the existing button template, we can learn about how the Microsoft-supplied controls handle state transitions. Click on the Pressed state and in the Object and Timeline view the State changes to Pressed and two Parts light up: Background Gradient and Downstroke.
Turning the arrows to open these two parts reveals what sub-parts are changed when the button moves into the Pressed state, as shown in Figure 6-13

Figure 6-13. Examining the Template for Button Pressed
Notice that under Background Gradient the Fill consists of four Gradient stops and that all four change their color, but the second also changes its offset. You can click on each color in turn and by looking at the properties window and/or the Xaml examine the change for yourself. This is especially interesting with the second, where the color and the offset changes, as shown in the composite image in Figure 6-14

Figure 6-14. Button Pressed State (Click to view full-size image)
Skinning A Control From A to Z
All of that is great, but let's create a complete template from scratch and see what happens. It is one thing to understand how it works and quite another to actually do it.
Let's return to the project we've been working on and do just a little fixing before we tackle skinning the button. If you've not done so already, drag the prompt style onto the five prompts (this will make the last two extend beyond the left margin, that is quite okay).
Once that is done, double click on the UserControl in Objects and TimeLine and grab the entire control's sizing handle on the far right and extend it to a width of about 500. You next want to resize the left column, and to make this easy, enter Split mode and just adjust the Max width from 150 to 250. Your control should now look more or less like

Figure 6-15. Ready to Skin the Change Book Button (Click to view full-size image)
Making a Round Button
We want to change the button from its normal shape to a very attractive ball with the word Change emblazoned on it. The ball will swell when we pass a mouse over it, and will twist and dip when we click on it. It will also dim its text when it is not enabled. Cool eh?
To get started, find the button in the Objects and Timeline tab (its name is Change) and right click on it. Choose Edit Control Parts → Create Empty as shown in Figure 6-16.

Figure 6-16. Creating an Empty Template for the Button (Click to view full-size image)
In the dialog box, name the new template RoundButon and place it in the Application (which will create a new resource in App.xaml).
Blend will switch into Template design mode, indicated among other ways by the presence of the bread-crumbs at the top of the screen. Your empty template will be started with a Grid. Our button is going to consist of an Ellipse that has text within it and that is filled with a linear gradient.
Begin by placing an ellipse in the grid, just as you would were you in normal design mode. Set the width and height to 75 as a good starting point, and set the alignment to stretch.
We want to fill the Ellipse with a radial gradient (as opposed to the default linear gradient). Click on the fill brush button, click on the gradient brush button, and then in the lower left corner of the Brushes tab, click on Radial gradient, as shown in Figure 6-17

Figure 6-17. Picking the Radial Gradient Brush
Depending on how comfortable you are with the tool, you can set the Gradient stops and the Gradient orientation in the Brushes window or, if you find it easier directly in the Xaml. Here's what it looks like in the Xaml when we're done:
<Ellipse Width="75" Height="75"
Margin="0,0,10,10" x:Name="ButtonEllipse" >
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.2,0.2" >
<GradientStop Color="White" Offset="0.2"/>
<GradientStop Color="Blue" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
Your ellipse should look something like

Figure 6-18. Ellipse with Radial Gradient
Next we want to add text (specifically the word Change!) to the button. To do so, drag a text block somewhere on top of the ellipse and then switch to the properties window, where you will size and position it, as shown in Figure 6-19

Figure 6-19. Properties set for the button
Figure 6-19 has been edited to fit, removing sections that were not changed
At this point your button should look more or less like Figure 6-20

Figure 6-20. Button with Text Added
Managing the Button's State
As discussed above, the button has four "Common states" and two "Focus states." The job now is only to set the button's appearance for each of those states and, if we wish, to set the timing for the transition between states.
MouseOver
Let's begin by having the button swell a bit when the mouse passes over it. This is a simple transform but we want to have it happen on the ellipse, so click on the ellipse in the Objects and Timeline, then in the Transform tab click on the scale button as shown in

Figure 6-21. Transforming the scale of the Ellipse
When you click on scale the x and y change to the value 1. By entering clicking on MouseOver and entering the value 1.2 in the X and Y you are telling Blend that in the MouseOver state the button swells by 20%.
To test this, click on Page.xaml in the bread crumbs to return to editing mode. Delete the existing change button and then click on the resources tab and drag your new button onto the canvas. Switch to properties and name your button Change (there is code that depends on having a button named Change) and start the application.
Without clicking the button, pass the cursor over it and back. It does enlarge, but it feels cartoonish. The change is too abrupt. Right click on the button and select Edit Control Parts→ Edit Template, putting yourself back into template editing mode. Notice that the default transition time is 0 seconds. Let's change that to 0.2 seconds and run it again. What a difference 2/10 of a second can make.
Pressed
Probably the most interesting and challenging design is what to do when the button is pressed. We'll keep it relatively simple and have the button turn and dip.
Click on Pressed to indicate that is the state you wish to set and click on the Ellipse to indicate that you wish to change the properties of the ellipse. In the properties window, click within the Render Transforms window on the second button (rotate) and set the angle to 25 degrees. Next, click on the first button (translate) and change the y from 0 to 5.
The dip is working fine, but there doesn't appear to be any rotation. Of course, how could we tell with a circle? You can return to the template and make the circle more elliptical (e.g., set the width to 90) which does verify that it s rotating, but it is an ugly effect.
An alternative is to rotate the text rather than the ellipse. This makes for a much more dramatic effect, as shown in Figure 6-22

Figure 6-22. Rotating the text on button press
You can accomplish this by switching back to the template. This time do so by switching to the Resources tab, expanding App.xaml and double clicking on RoundButton. Now you can click on ButtonEllipse, and undo the rotation and then click on ButtonText and set the rotation. Very nice.
Disabled
The last state to set within the Common states is Disabled. Click on the ButtonText, and let's change its color from white to grey to indicate that the button is disabled. Because the color change should happen pretty quickly, click on the AddTransition button within the Disabled button as shown in Figure 6-23

Figure 6-23. Adding a Transition
Choose the first option (from any state to disabled) and set the time to 0.1 seconds. Click the Add Transition button again, and this time choose Disabled → * and set the transition back to any state to 0.1 seconds as well; the states window should look like Figure 6-24

Figure 6-24. State Transition Window with Custom Transition Times
More to come
Future tutorials, videos and blog posts will build on what we've covered so far, including:
- Use of the content presenter
- Dynamically setting values in template controls
- In-state and inter-state animation
- The VSM and Custom controls
And much more.