You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于IsMouseOver触发器切换图片的Button使用TemplateBinding失效问题

解决WPF通用化图片切换Button失效问题

问题原因

你通用化后的代码失效,是因为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:05:07