Custom button template in WPF Custom button template in WPF wpf wpf

Custom button template in WPF


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.


I have finally created a Button with image + text inside it:

Below is the Full Code:

Step 1 : Create a new User Control called:ImageButtonUC

<UserControl Name="ImageButton" x:Class="WpfApp.ImageButtonUC"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">    <Grid>        <Button VerticalAlignment="Top" Width="100" Height="25" Click="button_Click">             <Button.Content>                <StackPanel Orientation="Horizontal">                    <Image Width="16" Height="16" Margin="5,0,5,0" Source="{Binding ElementName=ImageButton, Path=Image}"/>                    <TextBlock Text="{Binding ElementName=ImageButton, Path=Text}"/>                </StackPanel>            </Button.Content>        </Button>    </Grid></UserControl>

Step 2: Edit ImageButtonUC.xaml.cs

public partial class ImageButtonUC : UserControl    {        public event RoutedEventHandler Click;        public ImageButtonUC()        {            InitializeComponent();        }        public string Text        {            get { return (string)GetValue(TextProperty); }            set { SetValue(TextProperty, value); }        }        public static readonly DependencyProperty TextProperty =          DependencyProperty.Register("Text", typeof(string), typeof(ImageButtonUC), new UIPropertyMetadata(""));        public ImageSource Image        {            get { return (ImageSource)GetValue(ImageProperty); }            set { SetValue(ImageProperty, value); }        }        public static readonly DependencyProperty ImageProperty =           DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButtonUC), new UIPropertyMetadata(null));        private void button_Click(object sender, RoutedEventArgs e)        {            if (null != Click)                Click(sender, e);        }    }

Step 3: In your xaml you can use it this way:Add the namespace as

xmlns:Local="clr-namespace:WpfApp"

And use it as:

<Local:ImageButtonUC x:Name="buttonImg" Width="100" Margin="10,0,10,0" Image="/WpfApp;component/Resources/Img.bmp" Text="Browse..." Click="buttonImg_Click"/>

Note: My Image is loacted in the Resources folder here

Reference:

http://blogs.msdn.com/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx


If you don't want to write any code-behind, there is another way of doing this (inspired by jeffora's answer). You can use the control's Content field to put the URI to the image you want to see in your button:

<Button Content="https://www.google.com/images/srpr/logo3w.png" Height="100" Width="200" Style="{DynamicResource ButtonStyle1}"/>

And then you can edit the default Button Style to look like this:

<Style>...<Setter Property="Template">    <Setter.Value>        <ControlTemplate TargetType="{x:Type Button}">            <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true">                <Image x:Name="theImage" Source="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" Margin="4,0,0,0">                    <Image.ToolTip>                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>                    </Image.ToolTip>                </Image>            </Microsoft_Windows_Themes:ButtonChrome>            <ControlTemplate.Triggers>                ...            </ControlTemplate.Triggers>        </ControlTemplate>    </Setter.Value></Setter></Style>

The magic is in the 'Source=(Binding ...}' part. It has worked well for me to have the ToolTip there for debugging missing/changed images -- but can easily be removed as well.