views:

543

answers:

2

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.

A: 

Hello,

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"&gt;
    <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

Archie
The downside though is that your control doesn't derive from button. So if you wanted to bind a Command for example, you'd need to add another dependency property. But if you just want an image and text that'll work fine.
Josh Einstein
+1  A: 

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

<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>

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.

jeffora
Thanks. i tried it using Control Template but didnt succeed.
Archie
You shouldn't need to use a control template. I did all that just using the standard WPF Button class.
jeffora