Friday, September 24, 2010

Windows Phone 7 Quick Tip #8 – Making your Images “Theme-able”

When building your Windows Phone 7 application you should be aware of the concept of themes.  I’ve got another Quick Tip coming up on using themes, however if you use the built in themes and you have any “metro” style graphics, you’ll need to make sure they work with the both built in light and dark color themes.  If you create your graphics with a white foreground so that it contrasts the ‘dark’ background on the phone, when the white or ‘light’ background is selected by the user your images will disappear.  One potential solution here is to create two graphics (both white and black ones) and then swap them out based upon the selected background color.  I don’t think any of us really likes that idea.

With the help of Bill Reiss I came up with a custom control using an OpacityMask that will allow your metro type icons to work with both the light and dark backgrounds that can be selected by the user on their phone.

Here’s the source code, simply cut-and-paste it into your project.

using System;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows;

namespace WolfBytes
{
    public class ThemeableImage : Grid
    {
        Rectangle _rectangle;

        public ThemeableImage()
        {
            _rectangle = new Rectangle();

            var bgBrush = Application.Current.Resources["PhoneBackgroundBrush"]
                               as SolidColorBrush;

            if (bgBrush.Color == Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF))
                _rectangle.Fill = new SolidColorBrush(Colors.Black);
            else
                _rectangle.Fill = new SolidColorBrush(Colors.White);

            Children.Add(_rectangle);
        }

        public ImageSource Source
        {
            get
            {
                if (_rectangle.OpacityMask != null)
                    return (_rectangle.OpacityMask as ImageBrush).ImageSource;
                else
                    return null;
            }
            set
            {
                _rectangle.OpacityMask = new ImageBrush { ImageSource = value };
            }
        }
    }
}

Then for usage simply create either a black or white (or I guess for that matter any color image) transparent PNG.  That image will then be used to either show or hide the pixels of either the Black or White background (as specified with the “PhoneBackgroundBrush” resource) based upon their opacity of the pixels in the image.

Then in your XAML you can reference the control by adding the namespace with something like:

xmlns:wb="clr-namespace:WolfBytes"

With that in place you can add the new control to your page or control with:

<wb:ThemeableImage Source="/Images/Camera.png" x:Name="CameraButton" />

Being the Silverlight MVP, Bill suggest using OpacityMasks may have an effect on the performance of your page if you are doing any animations so you may want to look at adding a bitmap cache.

-twb

No comments:

Post a Comment