Click here to Skip to main content
Click here to Skip to main content

WPF Skinning Gotchas

, 9 Aug 2007 Ms-PL
Rate this:
Please Sign up or sign in to vote.
The following article documents my personal opinion on skinning using styles & resources. It also documents some of the gotchas I ran into while skinning an already existing application

Introduction

After reading Josh Smith's skinning article I decided to try it out on one of my real-world applications. I had an application that I re-deployed to more than one client and needed the application to suit my client's colour schemes. After a few trial and error sessions I decided to share my gotchas I ran into...

Resources and Styles Overview

WPF skinning relies very heavily on Resource and Style, so I will give you a quick overview of what Resources and Styles are.

Resources

Resources basically allow us to define "static value" or "const value" in XAML. A resource dictionary is a key-value pair list. It is more commonly used to store various styles target at specific elements or element types.

One very important thing to remember about resources is that they are only available in the element that they are defined and within its children. The FindResource basically recursively searches through the element tree. If no resource is found, it finally searches through the applications resources. This forms the fundamental basis of the WPF skinning.

Styles

Styles provide an easy way to change multiple properties of controls. Styles are essentially a collection of property values that are applied to elements. Charles Petzold also describes styles as a partial compensation for not being able to use loops in XAML to create multiple elements with identical properties.

The Gotchas

The first gotcha I ran into stems from the use of Dependency properties. Read the following article about Dependency properties and pay special attention to the explanation of how the order of precedence works because you actually only see the effect once you start playing round with skinning...

Under the hood: Dependency Properties

Suppose you have an already created application with a button, then this button might be placed somewhere in a container (i.e. Grid). The position of this button can be determined by various methods but the most commonly used, is the Margin property. This property specifies the distance from the borders. This is all great, but what if I now want to skin this application? You need to remove all the locally set properties from all the controls you want to skin. If you just asked why, then you will have to read the dependency properties article again...

Let me explain: Styles have a lower order of precedence than locally values. If you don't remove the locally supplied values then your style will have no effect!!!

Well that is simple; I will just remove all the local values from the controls that I want to transform using styles... This might complicate your application just a little! If you never want to move your controls and all your buttons are always at the same position then this is not an issue though...

Screenshot - Chaos.jpg

Another point to keep in mind if you dynamically need to change the position of your controls (i.e. Button): You will need to create a base style for all your buttons (The look & feel of all the buttons) and then create multiple styles based on the base style and then only change the position depending on the use. As an example, imagine you have a Cancel and OK button. For each skin these buttons gets positioned at different positions. You will now have to create a base button style with the common look and feel for each skin and then also a separate style just for the OK button and the same for the Cancel button. Again, this might get much more complicated if you have more buttons!

The next problem I ran into is a little less technical. My first skin requires my main Window to have a logo image and a button, no problem. My second skin is a little more complicated. This skin requires a header, footer and a decoration image. To now design a form that can be transformed like this using styles get a lot more complicated. I now have to accommodate 3 images of which 1 could be used as a header or a logo image and the other 2 are footer and a decoration images. If the skin doesn't need a decoration image, then it would just be ignored...

Screenshot - Skin1.jpg
Skin 1

Screenshot - Skin2.jpg
Skin 2

The last thing I struggled with a little was animations. Each skin had a few animations that I wanted to trigger. I used to trigger these animations on Window loaded event but obviously this couldn't be used anymore. I now had to start these animations manually! I now had to use FindResource to look for my common animations (i.e. ProgramStartAnimation) and then cast it to a Storyboard. You must also now verify that the resource found is valid, because not all skins will have all the animations and then fire them.

Storyboard animation = (Storyboard)app.FindResource("ProgramStartAnimation");
if (animation)
    animation.Begin(this);     

Conclusion

I actually only saw the real power of WPF skinning when I started converting my second Window. On this Window I had a list box and a Done button. WPF skinning allowed me to very easily convert my 1st skin to create a large icon wrapped list box and for my second skin, I used a more conventional list box and only changed the highlighting colours. It was great to see how easily I could change these types of control behavior.

Even considering these gotchas I still feel that the WPF skinning is very useful. It should be sufficient for about 70% of all your skinning requirements. Thank you to Josh Smith for writing an excellent introductory article. Read it again and start skinning some of your applications...

Since this was my fist article for codeproject, please leave comments on how I can make it better... any suggestion, good or bad will help me to write better articles in the future...

PS: Also please rate the article... even if you thought it sucked!

Useful Blogs

History

  • 9-August-2007 - First draft
  • 12-August-2007 - Added some images & updated the conclusion

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

rudigrobler

South Africa South Africa
No Biography provided

Comments and Discussions

 
GeneralSkinning Pinmembernorm .net9-Aug-07 21:29 
I've another tip for skinning. I have created a menu style application for launching applications.
I've allow 2 themes Black and Blue. Now if you look at the wpf 'login' application, it uses resources that are loaded at run time. The trick was how to you create and link you own resource files like the ones in the sample. After an hour I manged to create a custom control (using the Add files...) then I hacked out the class.
 
The sources is
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
namespace SystemMenu
{
///
/// Interaction logic for BlueSkin.xaml
///

 
public partial class BlueSkin
{
public BlueSkin()
{
InitializeComponent();
}
 
}
}

 
and the XAML is
 

 






 
... etc etc

 
Now when I need to change the skin I just
 

Application.Current.Resources = new BlueSkin();
 

Cool, I dunno if this is helpful or not.

 

Roger Irrelevant
"he's completely hatstand
"

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.141015.1 | Last Updated 10 Aug 2007
Article Copyright 2007 by rudigrobler
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid