wpfcustom-controlsstyles

Custom button template in WPF


I want to create a simple button template with an image and text inside it. But I want to keep the System button's look and feel.

How do I create it, step by step?

P.S.: I have already tried it with CustomControl in WPF and BasedOn property.


Solution

  • You can do this easily with a style and attached property:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ap="clr-namespace:MyProject.Namespace.Path.To.ButtonProperties">
        ...
        <Style x:Key="ImageButton" TargetType="Button">
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Path=(ap:ButtonProperties.Image), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></Image>
                            <ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></ContentPresenter>
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        ...
    </ResourceDictionary>
    

    and

    public class ButtonProperties
    {
        public static ImageSource GetImage(DependencyObject obj)
        {
            return (ImageSource)obj.GetValue(ImageProperty);
        }
    
        public static void SetImage(DependencyObject obj, ImageSource value)
        {
            obj.SetValue(ImageProperty, value);
        }
    
        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(ButtonProperties), new UIPropertyMetadata((ImageSource)null));
    }
    

    Then in markup:

    <Button Style="{StaticResource ImageButton}" ap:ButtonProperties.Image="{StaticResource MyImage}" Content="Test">
    </Button>
    

    This example looks pretty hideous, but you can easily change the StackPanel to a Grid or something similar to constrain the image proportion. Using the ContentPresenter allows you to preserve the behaviour of a button allowing you to put any UIElement inside, and retaining Command support etc.