Rigging up ThemeableImage in Windows Phone Applications

I started overhauling my infamous Windows Phone user group prize picking application, dfRandomWinner, yesterday. One particular screen called for use of an image. The image I was looking at using is a black and white image (see below). I want my applicaiton to respect theming on the phone. Which means I would have had to have two images, one black, one white, and used a technique to switch the images based on the theming background.

As I pondered this, I remembered a post by Kevin Wolf with a ThemeableImage control in.  The ThemeableImage adapts the control based on the theme's background color. Kevin's control uses an Opacity mask to filp the colors on the image based on the theme. His article (with source code) can be found here https://new.efficientcoder.net/2010/09/windows-phone-7-quick-tip-8-making-your.html . I'm going to walk you through rigging up the ThemeableImage in your project.

Step 1 - Create a metro styled image (black) - ours is named dfrandomwinner.black.png - see a picture below
Step 2 - Create a new Window Phone 7 project
Step 3 - Create an images directory in the project, then add the image to the directory
Step 4 - Modify the properties and make the image "Content", "Copy Always"
Step 5 - Add a new empty class called ThemeableImage.cs to the project
Step 6 - Go to Kevin's blog and copy the ThemeableImage class into the clipboard
Step 7 - Paste Kevin's code into ThemeableImage.cs
Step 8 - Modify the namespace statements at the top of MainPage.xaml to reference our assembly

     xmlns:wolf="clr-namespace:WolfBytes;assembly=WolfBytes"

Step 9 - Modify MainPage.xaml to show a regular Image control, and the ThemeableImage side by side - XAML below

     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" 
      HorizontalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="220"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="220"/>
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0" HorizontalAlignment="Center">
            <Image Width="200" Source="/images/dfrandomwiner.black.png" />
            <TextBlock Text="Image" HorizontalAlignment="Center"/>
        </StackPanel>
        <Rectangle Grid.Column="1" Width="5" Height="540" Fill="AliceBlue"/>
        <StackPanel HorizontalAlignment="Center" Grid.Column="2">
            <wolf:ThemeableImage x:Name="DFRandomWinnerImage" Width="200" 
              Height="200" Source="/images/dfrandomwiner.black.png" />
            <TextBlock Text="ThemableImage" HorizontalAlignment="Center"/>
        </StackPanel>
    </Grid>

Step 10 - Build and run in the emulator With the black background the ThemeableImage will be white
Step 11 - Hit the back button to stop the app. Go into settings, change the theme to White, run the app again by double click on it. The image will be black on a white background

As you can see once you've rigged up ThemeableImage, it can save you a ton of work in setting up your projects. I don't have to create two sets of images. Nor do I have to do any pathing tricks for referencing multiple image directories. It'd be nice to see ThemeableImage make the Windows Phone Toolkit. In the meantime, you can use this post as a reference for rigging up the ThemeableImage in your projects.

themeable.baseimage Base image with transparent areas themable.blackback Image rendered on black theme themeable.whiteback Image rendered on white theme