Mobile Zone is brought to you in partnership with:

Tim Dams is a teacher at the Artesis University College in Antwerp, Belgium where he is mainly involved in software engineering and programming courses. In his spare time he likes to write Silverlight, WPF and Windows Phone 7 applications and blog about the things he learns in the process. Tim is a DZone MVB and is not an employee of DZone and has posted 19 posts at DZone. You can read more from them at their website. View Full User Profile

Creating a WP7 app: Supporting dark and light themes

01.28.2012
| 3234 views |
  • submit to reddit
In this post I will show how to create an application that supports both the dark and the light themes, without the hassle of creating two sets of images, icons or styles.

This post is part of a series of posts I’ve planned on my findings while writing a windows phone 7 application (see the previous post, on the problem of caching urls, here).

Colors and themes

Owners of a WP7 device can choose whether they have a dark theme of a light theme while using the phone. Users can change this anytime they feel like it. As a WP7 developer your application will need to take into account that both themes can be active. In this post I will only concentrate on the background color which can be dark or light, and ignore the accent color.



When your application starts up, the current active theme will influence the way your application looks. That is, as long as you haven’t explicitly defined certain styles and colors, all the standard WP7 controls will show up in a correct manner. Let’s see how this works. Suppose your extremely cool and intuitive application has a nice shiny button such as this:

<Button Content="Shiny"/> 



The button will have a look dependent of what theme is being used (note that the accent color of the theme doesn’t matter here). So if we run our application we will see the following buttons:

When the dark theme(left image) is active our button, and all other standards controls, will automatically have a black background and white foreground brush. However, when the light theme is active, what WP7 basically does is switch the Foreground and the Background property of all controls, as long as they’re not defined explicitly.

The moment however, you define a specific color for a control, WP7 won’t help you with switching colors anymore and making sure your controls will look ok in the active image.
Imagine a fancy yellow button:

<Button Content="Shiny" Background="Yellow"/>

 

Testing this button in the white theme gives pleasant results (make note: I’m not designer, I’m already happy if my color schemes don’t induce a headache within 5 minutes):

Now let’s see how this looks like in the dark theme:

Ugh..My eyes! What happens is, since we didn’t define the Foreground explicitly (which the text and border in the button uses) the black borders and black content were switched, but the yellow background was not. Still, ugly or not, the button is still sort of useable.

However, suppose you really need your button to have a specific color…for example white.

<Button Content="Shiny" Background="White" Button>



Let’s see what this looks like in the both themes:

Yippie, we made a white rectangle!

Anyhow, you get the point. In summary: If you are planning on playing with colors, you better be prepared to write two different styles that will vary according to the theme being is. Let’s see how we can cope with the fact that your phone can have a dark and light theme.

Detecting the theme

To know which theme is active I’ve seen several tricks (old-school style is apparently by looking at the current RGB values of the fore-or background brush) but in my opinion, the following is the most straightforward (see here for a list of all predefined theme resources):

bool dark= ((Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible)

We can simply check whether the PhoneDarkThemeVisibility is Visible or not (the “PhoneLightTheme” that also exist will have the opposite value). If it is, we now what the current theme is. We can do 2 things, depending on the type of buttons being used,:

  • Load in a new style for your controls.
  • Work with images that replace the back-and foreground of the buttons.

Load new style

A lot has been written on how to change the theme of your controls at runtime, so in summary what needs to be done is something along the lines of:

  1. Create 2 brushes or styles, one for each theme, and place them in your application resources (App.xaml file)
  2. When you need to change to the other theme, remove the current brush or style from your application, e.g.:
    App.Current.Resources.Remove("MyCurrentTheme");
  3. Insert the other brush or theme in your application, e.g.:
    App.Current.Resource.Add("MyCurrentTheme", mydarkTheme)

Images and themes

The problem described earlier with buttons looking like ugly betty also applies to images. Suppose you created a nice transparent image to be used in your button:

The black part of the image is transparent. Using this button in the dark theme gives pleasant results:

<Button>
component/home_white.png">
</Button>

 

In fact, thanks to the transparency, we can do fun stuff like:

<Button Background="Green">
component/home_white.png">
</Button>

 

However, if we don’t explicitly defined a background (why should you? Remember, Metro design is all about no chrome and other silly non-usable UI changes…check out your iPhone or Android to see what I mean :p ) and then switch themes, we again have created a very white rectangle:

We can solve this problem in 2 ways:

  1. Have a different set of images for both themes
  2. Have one set, but toy around with transparency

Image sets

Having two sets of image has the benefit of knowing exactly what each button (or control) will look like in each theme. The drawback is that every time you change one image, you also have to change the other one.Still, from time to time this is how things go. To work with image sets, the most straightforward solution , a variation from here, goes as follows:

  1. Create 2 sets of images and include both as assets, content or resources to your solutions. Keep all names the same, but only change the folder in which they reside (e.g. “buttons/dark/” and “buttons/light”).
  2. When initializing the page or application, query the phone which theme is used. (see earlier).
  3. Load in the correct set of images

How to do this in practice? Suppose we defined a button somewhere in our UI as follows:

<Button >
<Image x:Name="btnImage" ></Image>
</Button>

 

Following code, which can be placed in the constructor of the page can then be:

Uri uri;
if ((Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible)
uri = new Uri("/buttons/dark/home.png", UriKind.Relative);
else
uri = new Uri("/buttons/light/home.png", UriKind.Relative);
btnImage.Source= new BitmapImage(uri) ;

 

Note that we could also easily refactor this code in order to define both folderlocations-strings (“button/dark/” and “button/light/”) elsewhere and only have to write the filename once (“home.png”);

One image set, changing transparency

For those among us, like me, who don’t really like to toy around in image, a third option exists to solve the changing themes problem, explained here and here (first answer). This solution, which I prefer above the ones explained earlier, goes as follows:

  1. Create a single set of black/white images
  2. Implement a style which changes the black/white colors of the images according to the active theme (in practice: change the active transparency from black to white or vice versa)
  3. Apply the style to all controls

The drawback of this method is that it only gives nice results for binary colored colored images. I suppose with a bit of extra coding this recipe can also be applied to other types of images, but it won’t be as straightforward.

In practice, 2 things are needed:

First , a new style is created which can then be applied to any button in the application. In short (full version here):

<phone:PhoneApplicationPage.Resources>
<Style x:Key="IconButton" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
<Setter Property="Padding" Value="10,3,10,5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
………….
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
<Grid x:Name="ContentContainer" OpacityMask="{TemplateBinding Content}" Background="{TemplateBinding Foreground}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

 

For now, let us zoom in on the main ‘trick’ in the style:

<Grid x:Name="ContentContainer" OpacityMask="{TemplateBinding Content}" Background="{TemplateBinding Foreground}"/>

What we created here is basically a new type of Button which uses an ImageBrush as its content, containing the image we want to be shown on the button. However, the style will make sure that we use an alphamask that uses the image as the mask (so make sure your image actually has an alpha channel; Tip: use PNG!). By setting the background color to the current Foreground color (dependent of the theme chosen) we make sure that the non-transparent portion of the image will have the correct color (what simply happens is that we ‘cut out’ the image from the foreground, using the alphamask).

All that remains now is applying this style to our controls (buttons in this example):

<Button Style="{StaticResource IconButton}" >
<ImageBrush ImageSource="/icons/home.png">
</Button>

 

If we now test our application we see that the button shows correctly, independent of the active theme. The picture on the left shows the dark theme:

 

Source: http://timdams.wordpress.com/2011/06/21/creating-a-wp7-app-supporting-dark-and-light-themes/ 

 

 

Published at DZone with permission of Tim Dams, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Lucie Hauri replied on Mon, 2012/03/26 - 4:47am

it is not so easy, but I will try to do it. I am sure that it is possible for a newbie like me. yacht charter mallorca

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.