Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF ImageButton

0.00/5 (No votes)
14 May 2014 1  
Creating WPF Image Button with WPF Custom Control

Introduction

This tip is about how to create WPF ImageButton simply and effectively. I used a WPF Custom Control for this tip.

To create this, we need to add an Image Control to the button content. We also want to be able to easily change that image and size from Code or XAML.

First Step: Create WPF Custom Control

For those unfamiliar with custom controls I must say, it's like making a new control, but we need to use a control as a Base Control. This way, we keep all Base Control features and then add new options to it or even change some features to make more comfortable controls for our usage. Create a new WPF Custom control library. Name it ExtendedButton (as an example). Your project contains the following parts:

  • CustomControl class: Contains code and inheritance from Control
  • Generic.xaml: Contain CustomControl Template. It is in Themes SubFolder

Second Step: CustomControl Class Code

After creating your project, you have the CustomControl1.cs class. Rename the class to ImageButton. Then rename your constructor and other CustomControl1, like the below code. Now we need to change base class from Control to Button. This inheritance defines our Base Control. I choose Button as the Base Control because it has all the features we need and also requires the minimum amount of work to became ImageButton. Although you can use any object as Base control which was inherited from Control Class.

public class ImageButton : Button
{
    static ImageButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), 
            new FrameworkPropertyMetadata(typeof(ImageButton)));
    }
}

For setting the image we need a property, which I named Image, but in the WPF Custom Control, we used Dependency Property (for more information, look at wpftutorial.net).

Also, we need two properties to set Image Size, for our new Control (ImageWidth and ImageHeight).

public ImageSource Image
{
    get { return (ImageSource)GetValue(ImageProperty); }
    set { SetValue(ImageProperty, value); }
}
public static readonly DependencyProperty ImageProperty =
    DependencyProperty.Register("Image",
    typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(null));
public double ImageHeight
{
    get { return (double)GetValue(ImageHeightProperty); }
    set { SetValue(ImageHeightProperty, value); }
}
public static readonly DependencyProperty ImageHeightProperty =
    DependencyProperty.Register("ImageHeight",
    typeof(double), typeof(ImageButton), new PropertyMetadata(Double.NaN));
public double ImageWidth
{
    get { return (double)GetValue(ImageWidthProperty); }
    set { SetValue(ImageWidthProperty, value); }
}
public static readonly DependencyProperty ImageWidthProperty =
    DependencyProperty.Register("ImageWidth",
    typeof(double), typeof(ImageButton), new PropertyMetadata(Double.NaN));

Important

  • Pay attention to the parameter which we use in the PropertyMetadata constructor. This parameter uses Default Value for property. So for some types we need set the correct value, like Image Property.
  • Dependency Property must register for custom Control. This done by the Register method and attaches to the Custom Control by the third parameter (in this overload) with type of CustomControl.

OK. We did everything we want to do with this class.

Third Step: Image Space Issue

Before we go for our Control Appearance, we need to do something about that image issue. Our control has an image and text so then if the control doesn't have any image, then we have an image control without any image (Blank Space). To prevent this issue, I created a simple convertor to check image value. If the image value is null, the image box will go invisible.

WPF has provided a feature for this solution and calls it Convertor. (For more information, look at wpftutorial.net). It's simple, just add a class to your project (name it VisibilityConvertor) then inherit your class from IValueConverter and, finally, implement it.

Now add a simple code for value checking to get this code:

public class VisibilityConvertor : IValueConverter
{
    public object Convert(object value, Type targetType, 
    object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return Visibility.Collapsed;
        return Visibility.Visible;
    }
    public object ConvertBack(object value, Type targetType, 
    object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

Fourth Step: Generic Class

Now we must define our new control appearance. To do this, we must go to Generic.xml in the theme directory. After creating a project, our Generic.xml will be like the code below:

<resourcedictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ExtendedButton">
<local:visibilityconvertor x:key="VisibilityConvertor" />
 <style targettype="{x:Type local:ImageButton}">
    <Setter Property="Template" > 
     <Setter.Value >
      <ControlTemplate TargetType="{x:Type local:ImageButton}" > 
        <Button >
            <StackPanel Orientation="Horizontal" > 
                <Image Margin="2 0" Source="{TemplateBinding Image}" 
                                       Width="{TemplateBinding ImageWidth}" 
                                       Height="{TemplateBinding ImageHeight}" 
                                       Visibility="{TemplateBinding Image,
                                       Converter={StaticResource VisibilityConvertor}}" 
                                       VerticalAlignment="Center"/ >
                <TextBlock Text="{TemplateBinding Content}" VerticalAlignment="Center"/ > 
            </StackPanel > 
        </Button > 
      </ControlTemplate > 
     </Setter.Value > 
    </Setter >
 </style>
</resourcedictionary>

Well done. Our custom control is ready and you can use it.

Points of Interest

As you see in custom control template, I use a button with a stack panel. But if you want to use the default button template, you can use the template I put in OtherTemplate file in sample. I produced that template with Microsoft Blend from a button and changed the content to stack panel. The difference between these templates is, you can access all the button appearances in the second template (like background and foreground).

So if you want to change it, you must only copy all styles and lines in OtherTemplate and replace the current template in Generic.Xaml.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here