基于IsMouseOver触发器切换图片的Button使用TemplateBinding失效问题
问题原因
你通用化后的代码失效,是因为ControlTemplate的Trigger中直接使用TemplateBinding无法正确解析绑定源。TemplateBinding是{Binding RelativeSource={RelativeSource TemplatedParent}}的简写,但在Setter的Value属性中,它的绑定上下文受限,必须显式指定RelativeSource=TemplatedParent来引用Button的属性。
修复后的Style代码
调整绑定方式,并修正初始图片的逻辑(你的Button中Content是悬停图,Tag是默认图,所以初始应显示Tag的内容):
<Style x:Key="ActionButton" TargetType="Button"> <Setter Property="BorderBrush" Value="{StaticResource BorderColor}"/> <Setter Property="BorderThickness" Value="2"/> <Setter Property="Background" Value="#FF220A5B"/> <Setter Property="Foreground" Value="#FFFFFF"/> <Setter Property="Height" Value="50"/> <Setter Property="Width" Value="50"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border CornerRadius="100" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"> <ContentPresenter.Content> <!-- 初始显示默认图片(绑定Tag属性) --> <Image x:Name="imagePresenter" Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}" Stretch="Uniform"/> </ContentPresenter.Content> </ContentPresenter> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <!-- 悬停时切换为Content属性指定的图片 --> <Setter TargetName="imagePresenter" Property="Source" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/> </Trigger> <!-- 无需额外写IsMouseOver=False的Trigger,默认状态会自动恢复初始绑定 --> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
自定义UserControl实现更优雅的通用化
如果想通过自定义属性实现(而非复用Content/Tag),可以创建带依赖属性的UserControl,这样设计器中能直接编辑属性:
1. 后台代码添加依赖属性
创建名为ImageToggleButton的UserControl,后台代码如下:
using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace YourProjectNamespace { public partial class ImageToggleButton : UserControl { // 默认图片的依赖属性 public static readonly DependencyProperty NormalImageSourceProperty = DependencyProperty.Register(nameof(NormalImageSource), typeof(ImageSource), typeof(ImageToggleButton), new PropertyMetadata(null)); // 悬停图片的依赖属性 public static readonly DependencyProperty HoverImageSourceProperty = DependencyProperty.Register(nameof(HoverImageSource), typeof(ImageSource), typeof(ImageToggleButton), new PropertyMetadata(null)); public ImageSource NormalImageSource { get => (ImageSource)GetValue(NormalImageSourceProperty); set => SetValue(NormalImageSourceProperty, value); } public ImageSource HoverImageSource { get => (ImageSource)GetValue(HoverImageSourceProperty); set => SetValue(HoverImageSourceProperty, value); } public ImageToggleButton() { InitializeComponent(); } } }
2. UserControl的XAML布局
<UserControl x:Class="YourProjectNamespace.ImageToggleButton" 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="50" d:DesignWidth="50"> <Button> <Button.Template> <ControlTemplate TargetType="Button"> <Border CornerRadius="100" Background="#FF220A5B" BorderThickness="2" BorderBrush="{StaticResource BorderColor}" SnapsToDevicePixels="True"> <Image x:Name="imagePresenter" Source="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=NormalImageSource}" Stretch="Uniform"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="imagePresenter" Property="Source" Value="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=HoverImageSource}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Button.Template> </Button> </UserControl>
3. 主XAML中使用
<!-- 先声明命名空间,local替换为你的项目命名空间 --> <Window xmlns:local="clr-namespace:YourProjectNamespace" ...> <local:ImageToggleButton NormalImageSource="/Resources/del-closed.png" HoverImageSource="/Resources/del-opened.png" Grid.Column="4" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Window>
内容的提问来源于stack exchange,提问作者ycsvenom
相关产品推荐
相关产品推荐

