How to create a button with image for Windows Phone
This article explains how to create a custom button with an image for Windows Phone.
Article Metadata
Code Example
Tested with
Compatibility
Article
Contents |
Introduction
There are many examples in the Windows Phone community showing how to create a button with an image. We can achieve this result with the following code:
<Button>
<Image Source="MyImage.png"/>
</Button>
The problem with the code above is that the Button can only display a single image: it cannot display a different (more appropriate) image when the button is disabled or pressed.
This article shows how to create (and use) the custom ButtonImage class to set a different image for the disabled and the pressed states. If you are not interested on the code of the ButtonImage class, you can skip this section and go directly to the #Usage section.
The button has an image for each state:
|
ButtonImage implementation
The ButtonImage class has XAML code and C# code.
XAML code
<Button x:Class="DotNetApp.ButtonImage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
IsEnabledChanged="ButtonIsEnabledChanged"
MouseEnter="ButtonMouseEnter"
MouseLeave="ButtonMouseLeave">
<Image Stretch="None"
HorizontalAlignment="Center"
VerticalAlignment="Center"
x:Name="image" />
</Button>
There is nothing fancy here, it is a button that has an image has content.
C# code
using System;
using System.Windows;
using System.Windows.Media.Imaging;
namespace DotNetApp
{
public partial class ButtonImage
{
#region Fields
public new static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof (bool), typeof (ButtonImage), null);
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof (string), typeof (ButtonImage), null);
public static readonly DependencyProperty ImagePressedSourceProperty = DependencyProperty.Register("ImagePressedSource", typeof (string), typeof (ButtonImage), null);
public static readonly DependencyProperty ImageDisabledSourceProperty = DependencyProperty.Register("ImageDisabledSource", typeof (string), typeof (ButtonImage), null);
private BitmapImage _image;
private BitmapImage _imagePressed;
private BitmapImage _imageDisabled;
private bool _isPressed;
#endregion
#region Constructor
public ButtonImage()
{
InitializeComponent();
}
#endregion
#region Properties
public new bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set
{
SetValue(IsEnabledProperty, value);
SetImageFromState();
}
}
public string ImageSource
{
get { return (string) GetValue(ImageSourceProperty); }
set
{
SetValue(ImageSourceProperty, value);
_image = SetImage(value);
SetImageFromState();
}
}
public string ImagePressedSource
{
get { return (string) GetValue(ImagePressedSourceProperty); }
set
{
SetValue(ImagePressedSourceProperty, value);
_imagePressed = SetImage(value);
SetImageFromState();
}
}
public string ImageDisabledSource
{
get { return (string) GetValue(ImageDisabledSourceProperty); }
set
{
SetValue(ImageDisabledSourceProperty, value);
_imageDisabled = SetImage(value);
SetImageFromState();
}
}
#endregion
#region Event Handlers
private void ButtonIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
SetImageFromState();
}
private void ButtonMouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
_isPressed = true;
SetImageFromState();
}
private void ButtonMouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
_isPressed = false;
SetImageFromState();
}
#endregion
#region Private Methods
private static BitmapImage SetImage(string imageSource)
{
BitmapImage bitmapImage = null;
if (!string.IsNullOrEmpty(imageSource))
{
bitmapImage = new BitmapImage(new Uri(imageSource, UriKind.RelativeOrAbsolute));
}
return bitmapImage;
}
private void SetImageFromState()
{
if (!IsEnabled)
{
image.Source = _imageDisabled;
}
else if (_isPressed)
{
image.Source = _imagePressed;
}
else
{
image.Source = _image;
}
}
#endregion
}
}
Once again, there is nothing "special" here. I load the correct images and based on the event handlers (ButtonIsEnabledChanged, ButtonMouseEnter and ButtonMouseLeave).
Usage
To use the ButtonImage control in your app, just follow those steps:
- Add the files ButtonImage.xaml and ButtonImage.xaml.cs to your project.
- Add the normal image, the pressed image and the disabled image to your project. If your button does not need a pressed image or a disabled image, you don't have to specify one.
- Add the XML code
<ButtonImageApp:ButtonImage ImageSource="/ImageNormal.png"
ImageDisabledSource="/ImageDisabled.png"
ImagePressedSource="/ImagePressed.png"
Style="{StaticResource ButtonImageStyle}"
Height="50"
Width="150" />
All the properties are important. The ImageSource, ImageDisabledSource, ImagePressedSource are the actual images that you want for each state. The Height and the Width need to be the same as the specified images.
The last piece of the puzzle is the Style property set to "{StaticResource ButtonImageStyle}". If you do not set this property, there will be an unwanted transparent area around the image and the image will be smaller. Your last step is to define the ButtonImageStyle into your project. You can add it into your page or in the App resources section. The code to copy is:
Page
<phone:PhoneApplicationPage.Resources>
<Style x:Key="ButtonImageStyle"
TargetType="ButtonImageApp:ButtonImage">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ButtonImageApp:ButtonImage">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground">
<ContentControl x:Name="ContentContainer"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>
or App
<Application.Resources>
<Style x:Key="ButtonImageStyle"
TargetType="ButtonImageApp:ButtonImage">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ButtonImageApp:ButtonImage">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground">
<ContentControl x:Name="ContentContainer"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Conclusion
The ButtonImage derives from a Button so you can add a Command or the Click handler.
Download
- File:ButtonImageApp.zip - The sample project including the ButtonImage control with an example on how to use it.






Hamishwillee - Subedited
Hi Sebastian
Nicely done!
Firstly, I've renamed because I think this makes it a tiny bit clearer that this is about creating a custom control. I've also merged the problem and solution description into the introduction because that makes the whole thing more readable. Lastly, moved up the image of what is created to the top so its even more obvious what is being created. I also linked to the Button control.
I like what you've done. In a couple of places you've stated that it isn't anything special, but I'm still learning C#, so I was a bit confused about the semantics of the DependencyProperty and why the sub class is "partial". I suspect this will be obvious within a day or two more of my learning :-0. IF it can be done without ruining the flow of the article and if you think it is reasonable, it might be worth adding a brief comment explaining the general "architecture" of how to create an overloaded control (ie to overload a control you create a partial class which does x,y,z etc)
regards
Hamishhamishwillee 10:38, 1 October 2012 (EEST)