Icons have been provided in the SDK for either "Light" or "Dark" depending on the theme set on the phone. On the application bar when the theme changes the icons automatically change with it. Also, when you press the button the image is reversed (so it's still visible) no matter which theme you're on. I can easily figure out how to change the icon based on the current theme. However what's no easily figured out is how to change the icon when the button is pressed.
To be more clear. Let's say I'm using the "Dark" theme. I create a button that uses the dark icon. When the button is pressed the background is white but the icon itself remains white and therefore is not visible. On the application bar the icon would become black which is of course visible against the white background.
Is this making sense? Anyone know how to fix this?
Instead of using light and dark icons you can use a single icon as an OpacityMask. This is just an example, you may want to make it into a separate control to make setting the icon neater, you can have C# code for a ToggleButton if you want. Also this series might be of some interest.
<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>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</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>
Usage
<Button Style="{StaticResource IconButton}" >
<ImageBrush ImageSource="appbar.feature.search.rest.png" Stretch="None"/>
</Button>
Explanation: An OpacityMask uses the alpha value of a brush for the element, as it takes a brush you could use a gradient or ImageBrush. In this case the ContentContainer which is rectangular takes the shape of supplied image, as only the alpha channel is used it can be any colour you want. The ContentContainer uses the foreground colour which the style changes when its pressed, you can change the icon colour by changing the buttons foreground. This style is basically the default but instead of a ContentControl a Grid with an OpacityMask is used instead.
Normally you wouldn't put an ImageBrush directly in a button but this is done as a quick workaround for some of the binding limitations in Silverlight v3. Alternatively you could use a custom control with a Uri property for an Icon which updates a Brush property for the mask. The style would use the custom Brush property as the OpacityMask instead of Button.Content. As the OpacityMask only uses the alpha channel this method isn't suitable for colour images.
Actually - WP7 has some smarts around it and will automatically make "dark" versions of light coloured icons (and also handle button press properly) provided the following conditions are met:
I'm using one set of icons in a WP7 app, and it handles light/dark themes automatically - there used to be an AppBarIcon pack from Microsoft as well, but a quick google is just giving me broken links at the moment. Send me an email if you're desperate and I can flick them your way.
While the suggested approach with OpacityMask probably works, it sounds a lot more difficult than just using white on transparent 48x48 pngs. :) Let me know how you go!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With