Vous êtes sur la page 1sur 23

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:

1. 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)
2. Create re-usable Style objects to enable a uniform appearance for controls that serve the
same function (e.g. all prompts look alike)
3. 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

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

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

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

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

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"

• Focused
• Unfocused

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

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

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

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.

Vous aimerez peut-être aussi