Skinning a Windows Presentation Foundation (WPF) App in Blend

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.

Skinning is the ability to change the look and feel of an application and enabling your WPF app to be skinnable involves taking into account certain factors which you'll familiarize yourself with as you go along.

Let's start skinning;
  1. 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.
  2. 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.
  3. Select the Rectangle tool from the Toolbox and draw out a rectangle on the window. Set the rectangle's Vertical Alignment to top.

  1. Rename the rectangle as 'Header' and give it a blue gradient Fill. Set its Stroke to No brush.

  1. Select the Window element and in the Brushes section of the properties panel set its Background to a gradient brush.

 

  1. 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 ResourceDictionaries that contain the different looks and feels 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 notice that there are no DynamicResources assigned to any of the properties of the elements in the application. This shall change as we go along.

ResourceDictionaries & Resources

In the following steps we shall create ResourceDictionaries and resources.

  1. Click on the Resources tab to open the Resources panel and click on the 'Create new resource dictionary' button.

  1. 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.
  2. Select the Window element in Objects and Timeline and open the Properties panel.
  3. 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.
  4. 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 switch to xaml view you will notice that the Background property of the Window element is assigned a DynamicResource named WindowBackground.

  1. 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.
  2. Name the new resource as 'HeaderFill' and select the 'Resource dictionary' option button. Click on Ok.
  3. Select the Resources tab to open the Resources panel. Create a new Resource Dictionary and name it as 'RedSkin.xaml'.
  4. Select the Window element and change the gradient brush of its Background to a reddish gradient.

  1. Click on the 'Advanced options' button of the Background property and select Convert to new Resource from the context menu.
  2. 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 look in the Resources panel and expand both BlueSkin and RedSkin.xaml, you 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.

  1. Select Header in Objects and Timeline and give its Fill a Red gradient.

  1. Click on the 'Advanced options' button of the Fill property and select Convert to New Resource from the context menu.
  2. 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 lets add the necessary coding to enable us to switch to the red skin at runtime.

Skinning a Windows Presentation Foundation (WPF) App in Blend

Coding

  1. Select the button we added to our application and in the Properties panel click on the Events button.

[Image10.jpg]

  1. 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.

[Image11.jpg]

  1. 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.

  1. Select the Resource panel tab and expand App.xaml.
  2. 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.
  3. Run the application. Click on the button. Notice that the interface changes to a reddish look.
  4. 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 Windows Presentation Foundation (WPF) App in Blend

Skinning a Control Object

In the following steps we shall skin our button control by using templates.

  1. Select the button object. Right click the button and select Edit Template > Create Empty.
  2. 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.
  3. Zoom in on the empty Control Template.
  4. Draw a rectangle in the empty grid and then right click it and select Auto Size > Fill. The rectangle should fill the whole grid.
  5. Rename the rectangle as BtnBackground and give it rounded corners.
  6. In the Properties panel ensure that the Properties button, and not the Events button, is active.B Change the StrokeThickness to 2 and change the stroke color to a white solid brush.
  7. Select Fill and change it to a blue gradient brush.

[Image12.jpg]

  1. Select the Assets button in the toolbox and select the ContentPresenter in the Controls section of the Assets window. The ContentPresenter is added to the toolbox.
  2. 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.
  3. 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.

[Image13.jpg]

  1. Change both gradient stops to white and adjust the alpha property of the last gradient stop to zero.

[Image14.jpg]

[Image15.jpg]

  1. In the Objects and Timeline panel click on the Up One Level button to return back to the Window.

[Image16.jpg]

  1. With the button object selected change its Content property to 'Red' and press enter. Then change its Foreground property to white. Save the project.

[Image17.jpg]

  1. 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 combo box of the 'Create ControlTemplate Resource' dialog.
  2. Select the button. Right click the button and select Edit Template > Edit a Copy.
  3. 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.
  4. In the button control template change the fill of BtnBackground to a red gradient.

[Image18.jpg]

  1. 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.
  2. 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.

  1. Stop the application if you haven't done so.
  2. Select the button object and copy-paste a new button onto our Window.
  3. Drag it and place it below the first button.
  4. Change the Content property of the new button to 'Blue'.

[Image19.jpg]

  1. 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.
  2. 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)
  1. 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.

  1. Right click the project in the Project panel and select Edit in Visual Studio from the context menu.
  2. Once Visual Studio opens right click the project in Solution Explorer and select Properties from the context menu. This opens the properties window.
  3. Select the Settings tab. Create a new setting named SkinPath of type String and scope of User. Leave the Value section blank.
  4. Double click on MainWindow.xaml.vb to open it for editing.
  5. Select 'MainWindow Events' from the Class Name combo box and Loaded from the Method Name combo box.
  6. B In the MainWindow_Loaded event procedure type in the following code,
    'Check whether SkinPath has a value and create
    'a resource dictionary...
    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
  1. In the Btn1_Click event procedure add the following code,
   My.Settings.SkinPath = "\RedSkin.xaml"
   My.Settings.Save()
  1. 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 an 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.

  1. Run the application.
  2. Change the skin to red and close the application.
  3. 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.

  1. When creating your user control you can expose the properties of an element that makes 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.
  2. 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.



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

  • A majority of organizations are operating under the assumption that their network has already been compromised, or will be, according to a survey conducted by the SANS Institute. With many high profile breaches in 2013 occurring on endpoints, interest in improving endpoint security is top-of-mind for many information security professionals. The full results of the inaugural SANS Endpoint Security Survey are summarized in this white paper to help information security professionals track trends in endpoint …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds