Better Theme-Aware Icon Buttons in Windows Phone 7

Claus points out in a comment below that you could also use the vector-formats that Microsoft provides with their icon files. Tidy solution. My opacity mask approach will still be useful where you have a partly-transparent raster image that you want to automatically render with the foreground color, regardless of the phone theme.

A few weeks back I posted a fairly hacky solution to have theme aware icon buttons (like the ones on the application bar). At the time, I knew there must be a better way. I’ve found it now.

The trick is to use the icon image as an opacity mask against a rectangle using the system foreground color. This way you don’t have to change the template at all, unless you actually want to change the image on the button.

So here’s the control template for a “play” button that will automatically change from black to white depending on theme. Note that we need two superimposed rectangles to cater for the circle and the icon. If you made composite png images, you’d only need one rectangle:

[code lang=”xml” wrap=”false”]
<ControlTemplate x:Key="PlayButton" TargetType="Button">
<Canvas Width="48" Height="48">
<Rectangle Fill="{StaticResource PhoneForegroundBrush}" Width="48" Height="48" >
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Content/Images/AppBarIcons/dark/appbar.transport.play.rest.png" />
</Rectangle.OpacityMask>
</Rectangle>
<Rectangle Fill="{StaticResource PhoneForegroundBrush}" Width="48" Height="48">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Content/Images/AppBarIcons/dark/appbar.basecircle.rest.png" />
</Rectangle.OpacityMask>
</Rectangle>
</Canvas>
</ControlTemplate>
[/code]

And here’s how you’d use it:

[code lang=”xml”]
<Button x:Name="PlayButton" Click="Play_Click" Template="{StaticResource PlayButton}" Width="48" Height="48" Margin="7" />
[/code]

MUCH more elegant than the previous solution.

8 Comments

  1. As I mentioned on Twitter, I would go with the vector graphics instead, as it’s easier to theme, and more lightweight

    Your example, modified:

    [code]
    <ControlTemplate x:Key="PlayButton" TargetType="Button">
    <Canvas Width="48" Height="48">
    <Path Data="F1M84.127,709.4629L70.558,719.8039L70.558,699.2159z" Fill="{StaticResource PhoneForegroundBrush}" Canvas.Top="14" Canvas.Left="17" Stretch="Fill" Height="20" Width="14" />
    <Ellipse Stroke="{StaticResource PhoneForegroundBrush}" StrokeThickness="1" Width="48" Height="48" />
    </Canvas>
    </ControlTemplate>

    <Button x:Name="PlayButton" Template="{StaticResource PlayButton}" Width="48" Height="48" />
    [/code]

  2. WP7 UX guidelines state that the circle will be added on top of the icon automatically by OS, so the icon shouldn’t contain it. Opart from that, thanks for a cool idea! :)

    • Yep that’s correct for application bar icons. But this is a follow-on from my original article where I’m using similar buttons within the main application frame. In this cas WP7 doesn’t automatically add the circle nor do the colour inversion for you.

  3. Hey, your tip is really cool for Buttons. But how would you proceed with buttons of type ApplicationBarIconButton?

  4. Should there be any reaction when clicking on the button?

  5. I know it’s an old thread, but any idea how you’d achieve the same effect from within the code-behind?

    Tried:

    Dim rect As New Rectangle With {
    .Width = 32,
    .Height = 32,
    .Fill = Resources(“{StaticResource PhoneForegroundBrush}”),
    .OpacityMask = New ImageBrush With {.ImageSource = New BitmapImage(New Uri(“/Images/appbar.check.rest.png”, UriKind.Relative))}
    }

    No joy though.

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

© 2015 Ben.geek.nz

Theme by Anders NorenUp ↑