具有奇怪行为的 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>
我有一个包含图像的简单按钮:
<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>