具有奇怪行为的 WPF 按钮的自定义悬停效果

Custom hover-effect for WPF button with strange behaviour

我有一个包含图像的简单按钮:

    <Button x:Name="helpBtn" Width="25" Style="{StaticResource HoverButton}" Template="{StaticResource hoverButtonTemplate}" Click="onHelpButtonClicked" ToolTip="{x:Static resx:language.HelpButton}" Height="25" BorderThickness="0" Canvas.Top="2" Canvas.Right="52" Canvas.Left="-77">
       <Image x:Name="helpImg" Source="Resources/2_help.png" Width="6" Height="10" Stretch="Uniform"/>
    </Button>

然后我有这个 ContentTemplate:

    <ControlTemplate x:Key="hoverButtonTemplate" TargetType="{x:Type Button}">
        <Grid>
            <ContentPresenter Content="{TemplateBinding Button.Content}" />
            <Rectangle x:Name="hoverRect2" Fill="DarkGreen" Visibility="Hidden" Opacity="0.2" Width="{TemplateBinding Button.Width}" Height="{TemplateBinding Button.Height}"></Rectangle>
            <Rectangle x:Name="hoverRect" Fill="Black" Visibility="Hidden" Opacity="1" Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Width}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Height}" Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Margin}">
                <Rectangle.OpacityMask>
                    <ImageBrush Stretch="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Stretch}" ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Source}"/>
                </Rectangle.OpacityMask>
            </Rectangle>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter TargetName="hoverRect" Property="Visibility" Value="Visible" />
                <Setter TargetName="hoverRect2" Property="Visibility" Value="Visible" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

问题是,鼠标指针总是需要在图像上移动(显示透明背景的小问号)。因此,在按钮的悬停效果可见之前,鼠标指针需要正好悬停在问号处。如果悬停效果激活并且鼠标离开问号但仍在按钮区域内,则一切都很好。这种奇怪行为的原因是什么?

WPF 不使用矩形的尺寸来检测鼠标是否在控件内部(悬停)。控件必须"catch" 以某种方式发生鼠标移动事件。在您的情况下,只需在 ContentPresenter 下方添加一个透明层。一旦检测到悬停,可见层 "catched" 鼠标事件。

    <ControlTemplate x:Key="hoverButtonTemplate" TargetType="{x:Type Button}">
        <Grid>
            <Rectangle Fill="Transparent"/>
            <ContentPresenter Content="{TemplateBinding Button.Content}" />
            <Rectangle x:Name="hoverRect2" Fill="DarkGreen" Visibility="Hidden" Opacity="0.2" Width="{TemplateBinding Button.Width}" Height="{TemplateBinding Button.Height}"></Rectangle>
            <Rectangle x:Name="hoverRect" Fill="Black" Visibility="Hidden" Opacity="1" Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Width}" Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Height}" Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Margin}">
                <Rectangle.OpacityMask>
                    <ImageBrush Stretch="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Stretch}" ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Source}"/>
                </Rectangle.OpacityMask>
            </Rectangle>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter TargetName="hoverRect" Property="Visibility" Value="Visible" />
                <Setter TargetName="hoverRect2" Property="Visibility" Value="Visible" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>