WPF自定义路由事件

如果是RoutedEvent,

先声明RouteEvent 指明RouteHandler名字和参数类型,

再定义事件包装器,说明处理的是RouteEvent,

自定义事件参数,需要传入事件,和调用该事件的element

或者逆向记忆

触发事件要传事件参数吧,你怎么知道这个参数传给谁,EventArgs里就要有

cs 复制代码
    /// <summary>
    /// 自定义路由事件
    /// </summary>
    public class TimeButton:Button
    {
        /// <summary>
        /// 声明和注册路由事件
        /// </summary>
        public static readonly RoutedEvent TimeEvent = EventManager.RegisterRoutedEvent("Time",//需要与包装器一致
 RoutingStrategy.Bubble, 
typeof(EventHandler<TimeEventArgs>), // 事件处理器类型
typeof(TimeButton));

        /// <summary>
        /// 事件包装器
        /// </summary>
        public event RoutedEventHandler Time{
            add { this.AddHandler(TimeEvent, value); }
            remove
            {
                this.RemoveHandler(TimeEvent, value);
            }
        }

        /// <summary>
        /// 重写方法,激发事件
        /// </summary>
        protected override void OnClick()
        {
            base.OnClick();
            TimeEventArgs e = new TimeEventArgs(TimeEvent,this);
            e.ClickTime = DateTime.Now;
            this.RaiseEvent(e);
        }

    }

    public class TimeEventArgs : RoutedEventArgs {
        public TimeEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) {

        }

        public DateTime ClickTime { get; set; }
    }


<local:TimeButton x:Name="timeButton1" Content="报时" Time="timeButton1_Time"></local:TimeButton>

private void timeButton1_Time(object sender, TimeEventArgs e)
{
       this.txtInfo.AppendText(string.Format("当前响应事件对象:{0},响应事件时间为:{1}\r\n", (sender as FrameworkElement).Name, e.ClickTime.ToString("yyyy-MM-dd hh:mm:ss.fff")));
}

RoutedPropertyChangedEvent(属性变化的路由事件)

通常与自定义依赖属性相结合

1. 确定泛型类型

RoutedPropertyChangedEvent 本质是针对特定类型属性变化的事件,需要指定泛型参数 T(例如 int、string、Color 等)。

2. 声明路由事件标识符

使用 EventManager.RegisterRoutedEvent 注册事件,事件处理器类型指定为 RoutedPropertyChangedEventHandler<T>(框架已定义的泛型委托)。

cs 复制代码
public class MyCustomControl : Control
{
    // 1. 声明路由事件标识符(静态只读)
    public static readonly RoutedEvent ValueChangedEvent = 
        EventManager.RegisterRoutedEvent(
            "ValueChanged",                   // 事件名称
            RoutingStrategy.Bubble,           // 路由策略(冒泡/隧道)
            typeof(RoutedPropertyChangedEventHandler<int>),  // 处理器类型(泛型为属性类型)
            typeof(MyCustomControl));         // 所属控件类型
}

3. 定义事件包装器

通过 add/remove 访问器包装,供外部订阅:

cs 复制代码
public class MyCustomControl : Control
{
    // 2. 事件包装器(名称与注册的事件名称一致)
    public event RoutedPropertyChangedEventHandler<int> ValueChanged
    {
        add { AddHandler(ValueChangedEvent, value); }
        remove { RemoveHandler(ValueChangedEvent, value); }
    }
}

4. 定义依赖属性

(通常与属性变化事件配套)

属性变化事件通常与依赖属性配合使用,当属性值变化时自动触发事件:

cs 复制代码
public class MyCustomControl : Control
{
    // 3. 定义依赖属性(属性变化的源头)
    public int MyValue
    {
        get { return (int)GetValue(MyValueProperty); }
        set { SetValue(MyValueProperty, value); }
    }

    // 依赖属性标识符
    public static readonly DependencyProperty MyValueProperty =
        DependencyProperty.Register(
            "MyValue",                  // 属性名称
            typeof(int),                // 属性类型
            typeof(MyCustomControl),    // 所属类型
            new PropertyMetadata(0, OnMyValueChanged));  // 默认值和变化回调

    // 4. 属性变化回调(触发事件的地方)
    private static void OnMyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyCustomControl control = (MyCustomControl)d;
        int oldValue = (int)e.OldValue;  // 旧值
        int newValue = (int)e.NewValue;  // 新值

        // 触发路由事件,传递旧值和新值
        control.RaiseEvent(new RoutedPropertyChangedEventArgs<int>(oldValue, newValue, ValueChangedEvent));
    }
}

5. 使用自定义的 RoutedPropertyChangedEvent

外部可以像订阅普通事件一样使用,并且能获取属性变化的旧值和新值:

cs 复制代码
<!-- XAML中使用 -->
<local:MyCustomControl MyValue="5" ValueChanged="MyControl_ValueChanged" />


// 后台代码处理事件
private void MyControl_ValueChanged(object sender, RoutedPropertyChangedEventArgs<int> e)
{
    Console.WriteLine($"属性值变化:从 {e.OldValue} 变为 {e.NewValue}");
    // 可通过 e.Handled = true 阻止事件继续传播
}

这种模式在 WPF 控件中非常常见,例如 Slider 的 ValueChanged、TextBox 的 TextChanged 等事件都是基于此实现的。

相关推荐
Scout-leaf2 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
武子康2 天前
大数据-236 离线数仓 - 会员指标验证、DataX 导出与广告业务 ODS/DWD/ADS 全流程
大数据·后端·apache hive
武子康3 天前
大数据-235 离线数仓 - 实战:Flume+HDFS+Hive 搭建 ODS/DWD/DWS/ADS 会员分析链路
大数据·后端·apache hive
DianSan_ERP3 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
够快云库3 天前
能源行业非结构化数据治理实战:从数据沼泽到智能资产
大数据·人工智能·机器学习·企业文件安全
AI周红伟4 天前
周红伟:智能体全栈构建实操:OpenClaw部署+Agent Skills+Seedance+RAG从入门到实战
大数据·人工智能·大模型·智能体
B站计算机毕业设计超人4 天前
计算机毕业设计Django+Vue.js高考推荐系统 高考可视化 大数据毕业设计(源码+LW文档+PPT+详细讲解)
大数据·vue.js·hadoop·django·毕业设计·课程设计·推荐算法
计算机程序猿学长4 天前
大数据毕业设计-基于django的音乐网站数据分析管理系统的设计与实现(源码+LW+部署文档+全bao+远程调试+代码讲解等)
大数据·django·课程设计
B站计算机毕业设计超人4 天前
计算机毕业设计Django+Vue.js音乐推荐系统 音乐可视化 大数据毕业设计 (源码+文档+PPT+讲解)
大数据·vue.js·hadoop·python·spark·django·课程设计
十月南城4 天前
数据湖技术对比——Iceberg、Hudi、Delta的表格格式与维护策略
大数据·数据库·数据仓库·hive·hadoop·spark