82

I want to change the background color of a button when IsMouseOver == True

    <Button Command="{Binding ClickRectangleColorCommand}" Background="{Binding Color, Converter={StaticResource RGBCtoBrushColorsConverter},Mode=TwoWay}" Width="auto" Height="40">
        <TextBlock Foreground="Black" Text="{Binding Color, Converter={StaticResource RGBCColorToTextConveter},Mode=TwoWay}"/>
          <Button.Style>
             <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
               <Style.Triggers>
                  <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="DarkGoldenrod"/>
                  </Trigger>
               </Style.Triggers>
             </Style>
         </Button.Style>
    </Button>

I can't seem to understand why this trigger isn't working.

mekb
  • 554
  • 8
  • 22
Gilad
  • 6,437
  • 14
  • 61
  • 119

5 Answers5

193

Try this- In this example Original color is green and mouseover color will be DarkGoldenrod

<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="50" Height="50" HorizontalContentAlignment="Left" BorderBrush="{x:Null}" Foreground="{x:Null}" Margin="50,0,0,0">
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Green"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="DarkGoldenrod"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
ctwheels
  • 21,901
  • 9
  • 42
  • 77
Microsoft DN
  • 9,706
  • 10
  • 51
  • 71
  • 3
    in 50 secs :) will do – Gilad Nov 19 '13 at 14:03
  • 7
    What exactly did OP do wrong? I want to know so I don't make the same mistake. – flarn2006 Aug 12 '15 at 18:48
  • @flarn2006 - I think is related with the Precedence of the dependency property over the trigger setter. Check out [this answer](http://stackoverflow.com/a/7126401/752842) – Dzyann Aug 31 '15 at 17:00
  • @flarn2006 I think it has something to do with the original default template's triggers. The trigger OP has will change the background for 1ms and then the story trigger kicks in and overwrites it – Steve Jan 16 '17 at 23:02
  • 1
    This removes the functionality of putting "_" in front of a buttons name and using it as a hotkey with the alt modifier. Anyone have a solution? – Scriven Jun 18 '17 at 17:23
  • 68
    WPF never ceases to amaze me with how much code and ceremony is required to do such simple things. Thanks for the answer though – Carlos Rodriguez Jan 23 '18 at 23:28
  • 32
    "WPF makes the hard trivial and trivial hard" – Njål Arne Gjermundshaug Apr 02 '19 at 18:15
  • 5
    It's unclear from this what part is necessary and why. There are 2 key things here: 1) you have to set the default values as Setters, not as explicit properties on the element, and 2) You have to set the Template in the style and bind the Border to the template. This is because a button has nested elements and the Border overrides the Template. It's weird, but that's WPF for you. – Mageician Jan 21 '20 at 16:04
  • 2
    It also has other strange side effects, like making the Padding on the button disappear because you've overridden the template. You can fix that by binding the ContentPresenter's Margin to the Template's Padding. – Mageician Jan 21 '20 at 16:11
  • 1
    Thanks for the answer. Makes me appreciate css all the more: `button:hover { background-color: white; }` – LOAS Jun 11 '20 at 08:32
  • Is there any reason why the background property is set to green in the style tag of the button and not on the button itself? If I remove `` and put a background property on the button directly, the mouseOver is not working. Do you know why? – Émile Pettersen-Coulombe Aug 24 '20 at 21:40
  • @CarlosRodriguez Yeah it's so far apart compared to easiness offered by CSS. We only need :hover. – Daniel Wu Jun 19 '21 at 11:35
27
<Button Content="Click" Width="200" Height="50">
<Button.Style>
    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="LightBlue" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="Border" Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="LightGreen" TargetName="Border" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Button.Style>

Trung Messi
  • 322
  • 3
  • 5
  • i.e.: Completely replace the style with a starkly minimalist re-implementation. (Took me a while to work through what this answer does). Great answer. I can see all sorts of applications for this sort of approach. It makes it much easier to re-use stock controls. – Robin Davies Apr 23 '20 at 13:41
  • 2
    The accepted answer didn't work, yours did. For those who also want to change the `Foreground`: default value = ``, trigger value = `` – Pollitzer Dec 19 '20 at 13:44
  • WTH, Accepted answer didn't work, but yours did. WPF is so strange, why if i set target to border it changes background? but if targetname isn't set, it does nothing? – ZecosMAX Apr 17 '22 at 20:19
5

As others already said, there seems to be no good solution to do that easily.
But to keep your code clean I suggest creating a seperate class that hides the ugly XAML.

How to use after we created the ButtonEx-class:

<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wpfEx="clr-namespace:WpfExtensions"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <wpfEx:ButtonEx HoverBackground="Red"></wpfEx:ButtonEx>
    </Grid>
</Window>

ButtonEx.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfExtensions
{
    /// <summary>
    /// Standard button with extensions
    /// </summary>
    public partial class ButtonEx : Button
    {
        readonly static Brush DefaultHoverBackgroundValue = new BrushConverter().ConvertFromString("#FFBEE6FD") as Brush;

        public ButtonEx()
        {
            InitializeComponent();
        }

        public Brush HoverBackground
        {
            get { return (Brush)GetValue(HoverBackgroundProperty); }
            set { SetValue(HoverBackgroundProperty, value); }
        }
        public static readonly DependencyProperty HoverBackgroundProperty = DependencyProperty.Register(
          "HoverBackground", typeof(Brush), typeof(ButtonEx), new PropertyMetadata(DefaultHoverBackgroundValue));
    }
}

ButtonEx.xaml
Note: This contains all the original XAML from System.Windows.Controls.Button

<Button x:Class="WpfExtensions.ButtonEx"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
            x:Name="buttonExtension">
    <Button.Resources>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="10" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
        <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
        <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
        <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
        <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
        <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
        <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
    </Button.Resources>
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsDefaulted" Value="true">
                                <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Background" TargetName="border" Value="{Binding Path=HoverBackground, ElementName=buttonExtension}"/>
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
                                <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
                                <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Style>
</Button>

Tip: You can add an UserControl with name "ButtonEx" to your project in VS Studio and then copy paste the stuff above in.

Sebastian Ax
  • 1,240
  • 12
  • 11
  • Very good answer, solved my problem, although I may suggest that you can set `HoverBackground`'s default value in xaml if you set the style's TargetType to `local:ButtonEx`. – Frank Z. Aug 22 '22 at 18:17
3

Adding on Microsoft_DN answer, if anyone wants to reuse the style for different buttons with different color we can create a custom Button class with hovercolor and bgcolor DependencyProperty.

HoverButton.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace StackOverflow
{
    public class HoverButton : Button
    {

        public static readonly DependencyProperty hoverColorProperty = DependencyProperty.Register
            (
                 "hoverColor",
                 typeof(SolidColorBrush),
                 typeof(HoverButton),
                 new PropertyMetadata(new BrushConverter().ConvertFrom("#5D5D5D"))
            );

        public SolidColorBrush hoverColor
        {
            get { return (SolidColorBrush)GetValue(hoverColorProperty); }
            set { SetValue(hoverColorProperty, value); }
        }

        public static readonly DependencyProperty bgColorProperty = DependencyProperty.Register
         (
              "bgColor",
              typeof(SolidColorBrush),
              typeof(HoverButton),
              new PropertyMetadata(new SolidColorBrush(Colors.Red))
         );

        public SolidColorBrush bgColor
        {
            get { return (SolidColorBrush)GetValue(bgColorProperty); }
            set { SetValue(bgColorProperty, value); }
        }
    }
}

Then add the following style in App.xaml file inside Application.Resources tag

<Style TargetType="{x:Type StackOverflow:HoverButton}" x:Key="customButton">
    <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path = bgColor}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Background="{TemplateBinding Background}">
                    <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"  Margin="{TemplateBinding Padding}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value ="{Binding RelativeSource={RelativeSource Self}, Path = hoverColor}" />
        </Trigger>
    </Style.Triggers>
</Style>

The we can use the style as in HoverButton

<myApp:HoverButton Height="20" Width="20" Style="{StaticResource customButton}" bgColor="Orange" hoverColor="Blue">
</myApp:HoverButton>

Because HoverButton is not using the project namespace we need to add

xmlns:myApp = "clr-namespace:StackOverflow" in both Application tag in app.xaml and Window tag in MainWindow.xaml file.

Sample: https://github.com/ayush1920/Stackoverflow/tree/main/WPF%20HoverButton

Ayush Kumar
  • 91
  • 1
  • 5
-2
<Button Background="#FF4148" BorderThickness="0" BorderBrush="Transparent">
     <Border HorizontalAlignment="Right" BorderBrush="#FF6A6A" BorderThickness="0>
     <Border.Style>
         <Style TargetType="Border">
             <Style.Triggers>
                 <Trigger Property="IsMouseOver" Value="True">
                     <Setter Property="Background" Value="#FF6A6A" />
                 </Trigger>
             </Style.Triggers>
         </Style>
      </Border.Style>
      <StackPanel Orientation="Horizontal">
           <Image  RenderOptions.BitmapScalingMode="HighQuality"   Source="//ImageName.png"   />
      </StackPanel>
      </Border>
  </Button>
Rarepuppers
  • 723
  • 1
  • 10
  • 21
shaiju mathew
  • 433
  • 5
  • 8