当鼠标悬停在按钮上时更改按钮的颜色

83

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>
我似乎无法理解为什么这个触发器不起作用。
5个回答

196

尝试这个 - 在这个例子中,原始颜色是绿色,鼠标悬停时的颜色将会是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>

3
在50秒内,我会进行翻译。 - Gilad
7
OP 做错了什么?我想知道,这样我就不会犯同样的错误。 - flarn2006
71
WPF 用于实现简单功能时需要编写的代码和程序实在太多了,这总是让我感到惊讶。不过还是感谢你的回答。 - Carlos Rodriguez
34
WPF使得难事变得轻松,简单的事情变得困难。 - Njål Arne Gjermundshaug
5
从这里不清楚哪一部分是必要的以及为什么。 这里有两个关键点:1)您必须将默认值设置为Setter而不是作为元素上的显式属性,2)您必须在样式中设置模板并将Border绑定到模板。 这是因为按钮具有嵌套元素,而边框会覆盖模板。 尽管很奇怪,但这就是WPF。 - Mageician
显示剩余7条评论

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>


完全用极简主义的重新实现风格替换。 (我花了一段时间才弄清楚这个答案的作用)。非常好的答案。我可以看到各种应用程序都可以使用这种方法。这使得重新使用库存控件变得更加容易。 - Robin Davies
2
被接受的答案不起作用,而你的起作用了。对于那些想要更改“前景”的人:默认值 = <Setter Property="Foreground" Value="Your color 1" />,触发器值 = <Setter TargetName="Border" Property="Button.Foreground" Value="Your color 2" /> - Pollitzer
WTH,被接受的答案不起作用,但你的起作用了。WPF太奇怪了,为什么如果我将目标设置为边框,它会改变背景?但如果未设置TargetName,则什么也不会发生? - ZecosMAX

5

就像其他人已经说过的那样,似乎没有简单易行的好解决方法。
但是为了保持您的代码整洁,我建议创建一个独立的类,用于隐藏丑陋的XAML代码。

在创建了ButtonEx类之后如何使用:

<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
注意:这里包含了System.Windows.Controls.Button中所有原始的XAML。

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

提示: 您可以在VS Studio中将一个名为 "ButtonEx" 的用户控件添加到您的项目中,然后将上面的内容复制粘贴。


非常好的答案,解决了我的问题,尽管我建议如果您将样式的TargetType设置为local:ButtonEx,则可以在xaml中设置HoverBackground的默认值。 - Frank Z.

3
在Microsoft_DN的回答上补充一点,如果有人想要重复使用不同颜色的样式来创建不同的按钮,我们可以创建一个自定义按钮类,其中包含hovercolorbgcolor依赖属性。

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); }
        }
    }
}

然后在 App.xaml 文件的 Application.Resources 标签内添加以下样式。
<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>

我们可以使用鼠标悬停按钮中的样式。
<myApp:HoverButton Height="20" Width="20" Style="{StaticResource customButton}" bgColor="Orange" hoverColor="Blue">
</myApp:HoverButton>

由于HoverButton没有使用项目命名空间,我们需要在app.xaml文件中的Application标记和MainWindow.xaml文件中的Window标记中分别添加

xmlns:myApp = "clr-namespace:StackOverflow"

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接