WPF - How to create image button with template

80,054

Solution 1

You won't need dependency properties because you are inheriting from Button. You already have the IsPressed and IsEnabled properties. In fact, this is all you need:

<Button x:Class="TestWpfApplication.ThreeStateImageButton"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Button.Template>
      <ControlTemplate TargetType="{x:Type Button}">
         <Grid>
            <Image Name="Normal" Source="Resources/Normal.png"/>
            <Image Name="Pressed" Source="Resources/Pressed.png" Visibility="Hidden"/>
            <Image Name="Disabled" Source="Resources/Disabled.png" Visibility="Hidden"/>
         </Grid>
         <ControlTemplate.Triggers>
            <Trigger Property="IsPressed" Value="True">
               <Setter TargetName="Normal" Property="Visibility" Value="Hidden"/>
               <Setter TargetName="Pressed" Property="Visibility" Value="Visible"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
               <Setter TargetName="Normal" Property="Visibility" Value="Hidden"/>
               <Setter TargetName="Disabled" Property="Visibility" Value="Visible"/>
            </Trigger>
         </ControlTemplate.Triggers>
      </ControlTemplate>
   </Button.Template>
</Button>

With your UserControl code-behind file:

public partial class ThreeStateImageButton : Button
{
   public ThreeStateImageButton()
   {
      InitializeComponent();
   }
}

Solution 2

 public static readonly DependencyProperty DefaultImageSourceProperty = DependencyProperty.Register("DefaultImageSource", typeof(ImageSource), typeof(PressedImageButton), new PropertyMetadata(null, new PropertyChangedCallback(DefaultImageSourceChangedCallback)));
    public static readonly DependencyProperty PressedImageSourceProperty = DependencyProperty.Register("PressedImageSource", typeof(ImageSource), typeof(PressedImageButton), new PropertyMetadata(null, new PropertyChangedCallback(PressedImageSourceChangedCallback)));
    public static readonly DependencyProperty ImageStretchProperty = DependencyProperty.Register("ImageStretch", typeof(Stretch), typeof(PressedImageButton), new PropertyMetadata(Stretch.None, new PropertyChangedCallback(ImageStretchChangedCallback)));

   <ControlTemplate>
        <Grid>
            <Image Name="imgDefault" Source="{Binding Path=DefaultImageSource,ElementName=uc}" Stretch="{Binding Path=ImageStretch,ElementName=uc}"></Image>
            <ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="Button.IsPressed" Value="True">
                <Setter Property="Image.Source" TargetName="imgDefault" Value="{Binding Path=PressedImageSource,ElementName=uc}"></Setter>
                <Setter Property="UIElement.Effect">
                    <Setter.Value>
                        <DropShadowEffect BlurRadius="10" Color="Black" Direction="0" Opacity="0.6" RenderingBias="Performance" ShadowDepth="0" />
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="Button.IsMouseOver" Value="True">
                <Setter Property="UIElement.Effect">
                    <Setter.Value>
                        <DropShadowEffect BlurRadius="10" Color="White" Direction="0" Opacity="0.6" RenderingBias="Performance" ShadowDepth="0" />
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

Solution 3

I have provided an alternative to this solution, its not quite as light weight but it offers much greater re-usability.

WPF TriState Image Button

Share:
80,054
Admin
Author by

Admin

Updated on March 11, 2020

Comments

  • Admin
    Admin over 4 years

    I am trying to create a button which has 3 images: a Normal image, a Pressed image and a Disabled image (I will use these for creating up/down arrow buttons).

    I believe the correct approach would be to derive from Button and use a Template and set triggers to change the image. I have 3 dependency properties, one for each image.

    The images would be .png and have transparent backgrounds (as they are not rectangular).

    I am looking for something like CBitmapButton in MFC.

  • Anderson Imes
    Anderson Imes almost 15 years
    Exactly. In fact, inheriting from Button is superfluous. You can do everything with this template and a style to apply it. The rule here should be if you need to change behavior, inherit and make a control. If you need to change "Look", then use a style.
  • Admin
    Admin almost 15 years
    Thank you for your response. This is what I was looking for.
  • dortzur
    dortzur about 13 years
    THANKS. This is the only Image Button solution that worked for me. I've even added a "Hover" trigger, Major Kudos!
  • Ash
    Ash almost 13 years
    when i am trying to add button template it shows error as the attachable property not found for button
  • surfen
    surfen about 12 years
    Nice solution. If anybody wondered about reusability, it's worth noticing that the image paths don't need to be hardcoded in style. If one ever needs to change something inside the style or template, for example change the button text or icon, one can use attached properties as suggested in this answer: stackoverflow.com/a/650620/724944
  • Guy
    Guy almost 12 years
    How can I pass the image src as a parameter so I can use this solution for different buttons, thanks
  • Hannish
    Hannish about 11 years
    The question clearly states that they need an image button with a template. A photoshop button does not constitute a template of any kind, an besides you don't need to handle the MouseEnter and MouseLeave events to change the cursor, you have the Cursor property for that. One more thing, don't asume that the normal cursor is an arrow, it might be something else, you can set the Cursor to null to return to normal.