I am trying to make an image button that changes the image when the mouse is over the button, i tried few things
this is the last thing I tried but it doesn't work:
<Button Name="fileNameLink" Margin="15,6,30,1" VerticalAlignment="Top" Click="btnMinimize_Click" MaxWidth="250" Background="Transparent" Cursor="Hand" Visibility="Visible" Height="16">
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel>
<Image Name="image1" Source="{StaticResource Minimize1}" Stretch="None" Visibility="Collapsed"/>
<Image Name="image2" Source="{StaticResource Minimize2}" Stretch="None" Visibility="Visible"/>
<StackPanel.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="image1" Property="Visibility" Value="Visible"/>
<Setter TargetName="image2" Property="Visibility" Value="Collapsed"/>
</Trigger>
</StackPanel.Triggers>
</StackPanel>
</ControlTemplate>
</Button.Template>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
i am tring to use the XAML only, without the cs file
Thanks
Your Trigger's are applied to the StackPanel
. It needs to be set on the ControlTemplate
Try:
<Button Name="fileNameLink"
Height="16"
MaxWidth="250"
Margin="15,6,30,1"
VerticalAlignment="Top"
Click="btnMinimize_Click"
Background="Transparent"
Cursor="Hand"
Visibility="Visible">
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel>
<Image Name="image1"
Source="{StaticResource Minimize1}"
Stretch="None"
Visibility="Collapsed" />
<Image Name="image2"
Source="{StaticResource Minimize2}"
Stretch="None"
Visibility="Visible" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="image1"
Property="Visibility"
Value="Visible" />
<Setter TargetName="image2"
Property="Visibility"
Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
In such cases. You can just use the Trigger
to set the Image
's source thereby not having to play with switching Visibility
on multiple UI element's.
something like:
<Button Name="fileNameLink"
Height="16"
MaxWidth="250"
Margin="15,6,30,1"
VerticalAlignment="Top"
Click="btnMinimize_Click"
Background="Transparent"
Cursor="Hand"
Visibility="Visible">
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Name="image"
Source="{StaticResource Minimize1}"
Stretch="None" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="image"
Property="Source"
Value="{StaticResource Minimize2}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
You will need a helper class to attach the image source property per button state and a style for your button. Put the helper class in a Helpers
folder in your WPF project.
Helper class
public static class ImageLoader
{
public static ImageSource GetDefaultImage(DependencyObject obj)
{
return (ImageSource)obj.GetValue(DefaultImageProperty);
}
public static void SetDefaultImage(DependencyObject obj, ImageSource value)
{
obj.SetValue(DefaultImageProperty, value);
}
public static readonly DependencyProperty DefaultImageProperty =
DependencyProperty.RegisterAttached(
"DefaultImage",
typeof(ImageSource),
typeof(ImageLoader),
new UIPropertyMetadata(null));
public static ImageSource GetHoverImage(DependencyObject obj)
{
return (ImageSource)obj.GetValue(HoverImageProperty);
}
public static void SetHoverImage(DependencyObject obj, ImageSource value)
{
obj.SetValue(HoverImageProperty, value);
}
public static readonly DependencyProperty HoverImageProperty =
DependencyProperty.RegisterAttached(
"HoverImage",
typeof(ImageSource),
typeof(ImageLoader),
new UIPropertyMetadata(null));
public static ImageSource GetDisabledImage(DependencyObject obj)
{
return (ImageSource)obj.GetValue(DisabledImageProperty);
}
public static void SetDisabledImage(DependencyObject obj, ImageSource value)
{
obj.SetValue(DisabledImageProperty, value);
}
public static readonly DependencyProperty DisabledImageProperty =
DependencyProperty.RegisterAttached(
"DisabledImage",
typeof(ImageSource),
typeof(ImageLoader),
new UIPropertyMetadata(null));
}
Button Style
<ResourceDictionary ...
xmlns:helper="clr-namespace:MySolution.MyWPFProject.Helpers"
...
>
<Style TargetType="{x:Type Button}" x:Key="MyButtonStyle">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<ContentPresenter Name="content"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
/>
<Border>
<!-- Default image -->
<Image Name="image" Source="{TemplateBinding helper:ImageLoader.DefaultImage}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand" />
<!-- Hover image -->
<Setter TargetName="image" Property="Source" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=(helper:ImageLoader.HoverImage)}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<!-- Disabled image -->
<Setter TargetName="image" Property="Source" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=(helper:ImageLoader.DisabledImage)}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Usage
<UserControl ...
xmlns:helper="clr-namespace:MySolution.MyWPFProject.Helpers"
...
>
<UserControl.Resources >
<ResourceDictionary Source="Path-to-my-button-style.xaml" />
</UserControl.Resources>
...
<Button helper:ImageLoader.DefaultImage="Resources/Images/MyDefaultImage.png"
helper:ImageLoader.HoverImage="Resources/Images/MyHoverImage.png"
helper:ImageLoader.DisabledImage="Resources/Images/MyDisabledImage.png"
Style="{DynamicResource MyButtonStyle}" />
...
You can achieve this by Image
style:
<Button Name="fileNameLink" VerticalAlignment="Top" Click="btnMinimize_Click" MaxWidth="250" Height="100">
<Button.Content>
<StackPanel>
<Image Name="image1" Source="{StaticResource Minimize1}" Stretch="None" >
<Image.Style>
<Style TargetType="Image">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Image Name="image2" Source="{StaticResource Minimize2}" Stretch="None" >
<Image.Style>
<Style TargetType="Image">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</Button.Content>
</Button>
Here is another approach to handle it using a specialized style. It should be pointed out, that this could be further improved with using attached properties for customizing the image files properly.
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Rectangle Fill="Transparent"/>
<Image x:Name="img" Width="64" Height="64" Source="a.jpg"/>
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="img" Property="Source" Value="b.jpg"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The Rectangle is important for the hit testing, otherwise the IsMouseOver won't trigger. And the Stretch on the ContentAlignment is necessary otherwise the ContentPresenter of the button would not span the whole button, therefore IsMouseOver wouldn't trigger again.