Introduction
In this tutorial, I will show you how to skin a WPF application in Expression Blend. The application you'll create will have a very simple UI, but the concepts you'll learn will enable you to skin WPF applications with more expansive user interfaces.
Background
Skinning is the process of adding functionality to an application that enables the user to change its look and feel at runtime. Skinning your WPF application involves taking into account certain factors which you'll familiarize yourself with as you go along.
Design
Let’s start skinning:
- Start Expression Blend and create a new WPF project named Skinning. Ensure that the Language is set to Visual Basic in the Language combo box.
- Select the
Window
element in Objects and Timeline, and in the Layout section of the Properties panel, set the width to 400 and height to 300.
- Select the Rectangle tool from the Toolbox, and draw out a rectangle on the window. Set the rectangle’s Vertical Alignment to top.
- Rename the rectangle as Header and give it a blue gradient Fill. Set its Stroke to No brush.
- Select the
Window
element and in the Brushes section of the Properties panel, set its Background to a gradient brush.
- Select the Button tool and draw a button in the
Window
element.
We will skin our app next by changing the current blue look to red. Skinning involves making use of ResourceDictionary
s that contain the different look and feel that you'd want for your application. A ResourceDictionary
is basically a collection of resources. A resource can be any of the properties of an object, or in the case of a control like a button, a style or a template. For a property to change when you add a new ResourceDictionary
, it must be assigned a DynamicResource
. A DynamicResource
changes at runtime when you switch from one ResourceDictionary
to another.
If you take a look at the XAML code for the application, you will notice that there are no DynamicResource
s assigned to any of the properties of the elements in the application. This shall change as we go along.
ResourceDictionaries and Resources
In the following steps, we shall create ResourceDictionary
s and resources.
- Click on the Resources tab to open the Resources panel, and click on the Create new resource dictionary button.
- In the New Item dialog, change the name of the new
ResourceDictionary
to BlueSkin.xaml. Click on OK. BlueSkin.xaml is added to the list in the Resources panel.
- Select the
Window
element in Objects and Timeline, and open the Properties panel.
- Click on the ‘Advanced options’ button that is next to the
Background
property in the Brushes section. Select Convert to New Resource from the context menu. This opens the Create Brush Resource dialog.
- In the Create Brush Resource dialog, change the name to
WindowBackground
and select the Resource Dictionary option button. Ensure that you have BlueSkin.xaml as the intended target in the combo box. Click on OK. If you now switch to the XAML view, you will notice that the Background
property of the Window
element is assigned a DynamicResource
named WindowBackground
.
- Select the rectangle we added. In the Properties panel, click on the Advanced options button of the
Fill
property and select Convert to New Resource from the context menu.
- Name the new resource as ‘
HeaderFill
’ and select the ‘Resource dictionary’ option button. Click on Ok.
- Select the Resources tab to open the Resources panel. Create a new Resource Dictionary and name it RedSkin.xaml.
- Select the
Window
element and change the gradient brush of its Background
to a reddish gradient.
- Click on the ‘Advanced options’ button of the
Background
property and select Convert to new Resource from the context menu.
- In the Create Brush Resource dialog, change the name to
WindowBackground
and select the Resource dictionary option button. Select RedSkin.xaml from the combo box and click on OK. Ignore the warning. If you now look in the Resources panel and expand both BlueSkin and RedSkin.xaml, you will notice that both resource dictionaries have resources with the same name.
Since WindowBackground
in BlueSkin
is a DynamicResource
, it will be swapped with WindowBackground
in RedSkin
when we change the resource dictionary. If the names were different, there would be no change in the background color since your application wouldn't know which resource to apply from the new resource dictionary.
- Select
Header
in Objects and Timeline, and give its Fill
a red gradient.
- Click on the ‘Advanced options’ button of the
Fill
property and select Convert to New Resource from the context menu.
- In the ‘Create Brush Resource’ dialog, change the name to
HeaderFill
and select the Resource dictionary option button. Select RedSkin.xaml from the combo box and click on OK.
Now that we have completed creating our Resource Dictionaries, let's add the necessary coding to enable us to switch to the red skin at runtime.
Coding
- Select the button we added to our application, and in the Properties panel, click on the Events button.
- In the Click event textbox, type ‘Btn1_Click’ and press Enter. Blend’s code editor opens for you to add the necessary code for the button’s click event.
- In the
Btn1_Click
event, type in the following code:
Dim RedSkin as New ResourceDictionary
RedSkin.Source = New Uri("RedSkin.xaml", UriKind.Relative)
Me.Resources.MergedDictionaries.Clear()
Me.Resources.MergedDictionaries.Add(RedSkin)
The code above creates a new resource dictionary named RedSkin
and assigns its source property the resource dictionary RedSkin.xaml that we created earlier. We then clear the MergedDictionaries
collection and add a new resource dictionary. MergedDictionaries
is a collection of ResourceDictionary
objects. If you have an application where you want to maintain the link to an existing resource dictionary, then avoid clearing the MergedDictionaries
collection, and instead of using the Add
method, type in the following code:
Me.Resources.MergedDictionaries(0) = RedSkin
This code places the resource dictionary in the first slot of the MergedDictionaries
collection.
- Select the Resource panel tab and expand App.xaml.
- Since our application is currently linked to RedSkin.xaml, we’ll remove this link. Right click ‘Linked To: RedSkin.xaml’ and select Delete from the context menu. Click on Yes in the resulting dialog box.
- Run the application. Click on the button. Notice that the interface changes to a reddish look.
- Close the application.
So far, we have managed to change the look of some of the elements in our application. The button object still looks the same even after we switch skins. Changing the look of a control is slightly different than changing the look of a shape object like a rectangle or ellipse. To change the look of a control object, we have to work with either styles or templates.
Styles allow us to change the look of a control, but limit us since we can’t directly access the elements that make up the control. Templates, on the other hand, allow us to directly manipulate the elements that make up a control. In a template, you can add, delete, or modify the elements that make up the overall structure of a control. Therefore, when skinning a control, you can choose to work with either styles or templates.
Skinning a Control Object
In the following steps, we shall skin our button control by using templates:
- Select the button object. Right click the button and select Edit Template > Create Empty.
- In the ‘Create ControlTemplate Resource’ dialog, leave the name as is, and select the Resource dictionary option button. BlueSkin.xaml should be the only value in the combo box as we deleted the link to RedSkin. Click on OK.
- Zoom in on the empty Control Template.
- Draw a rectangle in the empty grid, and then right click it and select Auto Size > Fill. The rectangle should fill the whole grid.
- Rename the rectangle as
BtnBackground
and give it rounded corners.
- In the Properties panel, ensure that the Properties button, and not the Events button, is active. Change
StrokeThickness
to 2
and change the stroke color to a white solid brush.
- Select Fill and change it to a blue gradient brush.
- Select the Assets button in the toolbox, and select the
ContentPresenter
in the Controls section of the Assets window. ContentPresenter
is added to the toolbox.
- Double click on the
ContentPresenter
tool in the toolbox to add it to the control’s grid. Set its Horizontal and Vertical alignments to center.
- Draw out another rectangle. Set its stroke to No Brush, then adjust it to look like the following image. Turn off snapping to snaplines if it’s giving you a hard time.
- Change both gradient stops to white, and adjust the alpha property of the last gradient stop to zero.
- In the Objects and Timeline panel, click on the Up One Level button to return back to the Window.
- With the button object is selected, change its
Content
property to ‘Red’ and press Enter. Then change its Foreground
property to White. Save the project.
- In the Resources panel, right click App.xaml and select Link to ResourceDictionary > RedSkin.xaml. Linking to RedSkin makes it visible in the Resource dictionary combobox of the ‘Create ControlTemplate Resource’ dialog.
- Select the button. Right click the button and select Edit Template > Edit a Copy.
- In the ‘Create ControlTemplate Resource’ dialog, change the name to
ButtonControlTemplate1
and select the Resource dictionary option button and RedSkin.xaml from the combo box. Click on OK.
- In the button control template, change the Fill of
BtnBackground
to a red gradient.
- Return back to the main window. Delete the link to RedSkin.xaml in the App.xaml section of the Resources panel. Click Yes in the resulting dialog.
- Run the project and click on the button. Notice now that all the elements in the application are skinned. A bit of animation would have served our button well to make it look like it’s lighting up during mouse over events, but you can do that in your free time.
It isn’t quite interesting that we can’t switch between our two skins, so let’s enable that.
- Stop the application if you haven’t done so.
- Select the button object and copy-paste a new button onto your
Window
.
- Drag it and place it below the first button.
- Change the
Content
property of the new button to ‘Blue’.
- Select the Events button of the Properties panel and type ‘
Btn2_Click
’ in the Click event textbox. Press Enter to open the code editor window.
- In the
Btn2_Click
event procedure, type in the following code:
Dim BlueSkin as New ResourceDictionary
BlueSkin.Source = New Uri("BlueSkin.xaml", UriKind.Relative)
Me.Resources.MergedDictionaries.Clear()
Me.Resources.MergedDictionaries.Add(BlueSkin)
- Run the project. Notice that clicking the two buttons allows you to switch between the two skins.
Saving State
The application is currently opening with the default skin, BlueSkin
, when you change the skin and close the application. In order to enable the application to open with the selected skin, we shall make use of application settings.
- Right click the project in the Project panel, and select Edit in Visual Studio from the context menu.
- Once Visual Studio opens, right click the project in Solution Explorer and select Properties from the context menu. This opens the Properties window.
- Select the Settings tab. Create a new setting named
SkinPath
of type String
and Scope of User. Leave the Value section blank.
- Double click on MainWindow.xaml.vb to open it for editing.
- Select ‘
MainWindow
Events’ from the Class Name combobox, and Loaded
from the Method Name combo box.
- In the
MainWindow_Loaded
event procedure, type in the following code:
If My.Settings.SkinPath <> String.Empty Then
Dim newDictionary As New ResourceDictionary()
Dim path As String
path = My.Settings.SkinPath
newDictionary.Source = New Uri(path, UriKind.Relative)
Me.Resources.MergedDictionaries.Clear()
Me.Resources.MergedDictionaries.Add(newDictionary)
End If
- In the
Btn1_Click
event procedure, add the following code:
My.Settings.SkinPath = "\RedSkin.xaml"
My.Settings.Save()
- In the
Btn2_Click
event procedure, add the following code:
My.Settings.SkinPath = "\BlueSkin.xaml"
My.Settings.Save()
In the MainWindow_Loaded
event procedure, we check whether the setting SkinPath
contains a value and create a resource dictionary whose source property is assigned a URI object that has the setting as the location of a resource dictionary. In the button click event procedures, we assign the setting SkinPath
with the location of the relevant resource dictionaries. We then persist the setting by calling the Save
method.
- Run the application.
- Change the skin to red and close the application.
- Run the application again. Notice that it now opens with the last skin we had applied.
Skinning UserControls
There are several steps you can take when it comes to skinning user controls.
- When creating your user control, you can expose the properties of an element that make up a control so that once you place the user control on your window, you can convert that property into a resource. To do this, use dependency properties.
- When creating a user control, create resources from the properties of the elements that make up the control, i.e., when the user control file is open in Blend, select the elements that you want to skin and create resources from the properties of interest.
In Conclusion
I hope that the tutorial was of great help, but I couldn’t finish without taking into account the debate over whether developers should also act as designers. My thought on this is that since Blend offers one the opportunity to put on both hats, why not do so. I am of the opinion that there is a developer out there who can also be a good designer, and vice versa.
External Links
History
- 4th May, 2010: Initial post.
- 23rd Jan, 2011: Article text updated.