《深入浅出WPF》:8.3.2 自定义路由事件 事件注册类型为 EventHandlerReportTimeEventArgs,但.NET 事件包装器类型为 RoutedEventHandler

image

事件处理器的签名要和注册时的签名一致:

image

包装器的参数类型为基类型,事件处理器的参数类型为子类型,根据委托协变,可以把子类型参数的委托赋值给基类型参数的委托
image

以下是deepseek回答:

这是一个非常好的问题,它触及了 WPF 路由事件中一个关于类型兼容性和历史设计的细节。

你的观察是准确的:代码中确实存在一个看似不一致的地方。我们来分析一下为什么可以这样做,以及为什么要这样设计。

核心原因:类型兼容性与 .NET 事件协变/逆变

  1. 事件注册时的类型

    public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));
    

    这里,RegisterRoutedEvent 方法的第三个参数是 handlerType,它指定了哪个委托类型可以处理这个事件。这里使用的是 EventHandler<ReportTimeEventArgs>。这意味着事件处理程序的签名必须是 void MethodName(object sender, ReportTimeEventArgs e)

  2. .NET 事件包装器

    public event RoutedEventHandler ReportTime
    {add { AddHandler(ReportTimeEvent, value); }remove { RemoveHandler(ReportTimeEvent, value); }
    }
    

    这里你发现,公共事件的类型是 RoutedEventHandlerRoutedEventHandler 的签名是 void MethodName(object sender, RoutedEventArgs e)

    那么问题来了:RoutedEventHandler 类型的委托怎么能被添加到期望 EventHandler<ReportTimeEventArgs> 类型委托的事件中呢?

  3. 关键的兼容性.NET 委托的协变

    • RoutedEventHandler 的参数是 RoutedEventArgs
    • 你的自定义参数 ReportTimeEventArgs 继承自 RoutedEventArgs
    • 在 .NET 中,委托支持协变。这意味着一个期望接收基类参数(如 RoutedEventArgs)的委托,可以安全地引用一个接收派生类参数(如 ReportTimeEventArgs)的方法。
    • 反过来,EventHandler<ReportTimeEventArgs> 可以被视为 RoutedEventHandler 的一个“更具体”的版本。因为任何能处理 RoutedEventArgs 的方法,必然也能处理它的子类 ReportTimeEventArgs(这是“里氏替换原则”的体现)。编译器允许这种赋值。

    因此,当你写 local:TimeButton.ReportTime="ReportTimeHandler" 时,XAML 编译器和运行时知道你的 ReportTimeHandler 方法符合 EventHandler<ReportTimeEventArgs> 的签名,所以它可以安全地工作。

为什么要包装成 RoutedEventHandler 类型?

既然技术上允许,那么设计上为什么选择 RoutedEventHandler 而不是 EventHandler<ReportTimeEventArgs> 呢?这主要是出于一致性和习惯

  1. 与 WPF 内置事件保持一致:WPF 中绝大多数路由事件(如 Button.ClickMouse.MouseDown)都使用 RoutedEventHandler 作为其公共事件的委托类型。即使它们的事件参数是更具体的类型(如 MouseButtonEventArgs 继承自 RoutedEventArgs),它们的公共事件也仍然定义为 RoutedEventHandler。你的自定义事件遵循了这一惯例,使得它看起来和用起来都像一个“标准”的 WPF 路由事件。

  2. 简化 XAML 书写:在 XAML 中,当你输入 Button.Click= 时,智能感知和编译器期望的是一个 RoutedEventHandler 类型的方法。如果你的自定义事件也使用 RoutedEventHandler,那么开发者在为你的 TimeButton.ReportTime 事件指定处理程序时,会有完全一致的体验。他们不需要去记忆一个特殊的 EventHandler<ReportTimeEventArgs> 类型。

  3. 历史原因EventHandler<T> 泛型委托是在 .NET Framework 2.0 中引入的,而 WPF 的部分设计可能更早,或者为了与早期的设计模式保持一致,选择了使用非泛型的 RoutedEventHandler。这个习惯被保留了下来。

总结

  • 技术上可行:因为委托协变,EventHandler<ReportTimeEventArgs>RoutedEventHandler 是兼容的。ReportTimeHandler 方法的签名最终匹配的是事件注册时指定的 EventHandler<ReportTimeEventArgs>
  • 设计上合理:将公共事件包装为 RoutedEventHandler 类型,是为了与 WPF 框架中其他所有路由事件保持一致,提供统一的编程体验。

所以,这并不是一个错误,而是一个遵循 WPF 惯例的、经过深思熟虑的设计。它保证了自定义路由事件在行为和用法上与原生事件无缝集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/919946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站转app工具高级版怎么分析网站建设的优缺点

Pytorch torchvision 包提供了很多常用数据集 数据按照用途一般分为三组&#xff1a;训练&#xff08;train&#xff09;、验证&#xff08;validation&#xff09;和测试&#xff08;test&#xff09;。使用训练数据集来训练模型&#xff0c;使用验证数据集跟踪模型在训练期间…

2025 自动售货机工厂推荐 配备 Bystronic 激光切割机,快速周转准时交货

在自动售货机生产领域,选择实力过硬的工厂是保障产品品质与合作效率的关键。2025 年,想要找到配备先进设备、拥有专业团队且能稳定交付的自动售货机工厂,东吉智能设备有限公司无疑是值得重点关注的选择。东吉智能设…

完整教程:探索 12 种 3D 文件格式:综合指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

完整教程:配送跑腿系统:构建高并发、低延迟的同城配送系统架构解析

完整教程:配送跑腿系统:构建高并发、低延迟的同城配送系统架构解析2025-09-27 21:05 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto …

网站建设与管理专业的行业发展惠州seo排名收费

场景在开发中我们经常需要对图片以人脸为中心进行剪切并显示&#xff0c;这时就需要下面这个工具了。实现效果实现效果项目参考及引用项目使用将下载的jar 和 .so 文件加入到项目中。API 说明在项目中使用如下API即可&#xff1a;CImageView这是一个继承ImageView的图片控件&am…

2019年云南建设银行招聘网站福建龙岩有哪些网络平台

问题&#xff1a; 在文件读取&#xff0c;判断md5值时&#xff0c;遇到py文件读取转String后&#xff0c;再转byte&#xff0c;md5前后不一致问题。 解决方法&#xff1a; python文件读取要使用QTextStream&#xff0c;避免\t 、\r、\n的换行符跨平台问题&#xff08;window…

自己做网站 需要会什么6做网站

Python中的collections模块 文章目录 Python中的collections模块1.Counter对象2.deque对象3.defaultdict对象4.namedtuple5.OrderedDictReference Python中的 collections提供许多容器数据类型&#xff0c;这个模块实现了一些专门化的容器&#xff0c;提供了对Python的通用内建…

wordpress兼容html5成品网站seo

文章目录 1. 机器学习简介1.1 机器学习是什么&#xff1f; 2. 机器学习分类2.1 监督学习2.2 无监督学习 3. 初识机器学习3.1 线性回归模型3.2 代价函数3.2.1 代价函数公式3.2.2 理解代价函数 4. 了解梯度下降算法4.1 梯度下降4.2 梯度下降的实现4.3 理解梯度下降4.4 学习率4.5 …

7.WPF 的 TextBox 和 TextBlock 控件 - 实践

7.WPF 的 TextBox 和 TextBlock 控件 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &quo…

惠州网站建设电话云商城是什么平台

D - Covering HDU - 6185 题意&#xff1a; 4 * n的地板&#xff0c;有无数个1 * 2 和2 * 1 的砖块&#xff0c;问有多少方式填满&#xff1f; 1≤n≤10^18 题解&#xff1a; 矩阵快速幂 代码&#xff1a;

关于【机器人小脑】的敏捷入门介绍

关于【机器人小脑】的敏捷入门介绍pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&…

企业门户网站建设论文seo排名价格

ui设计需要学编程吗难不难学习&#xff0c;对于基础小白来说学习编程确实有一定难度&#xff0c;所以很想知道零基础学习ui设计需要学编程吗&#xff0c;需不需要写代码呢&#xff0c;这些问题小编来简单的分析分析解决零基础小白的一些困惑&#xff0c;希望对你有帮助。 ui…

广东省建设安全中心网站网站访问量统计工具

背景 机器学习模型对数据的分析具有很大的优势&#xff0c;很多敏感数据分布在用户各自的终端。若大规模收集用户的敏感数据具有泄露的风险。 对于安全分析的一般背景就是认为有n方有敏感数据&#xff0c;并且不愿意分享他们的数据&#xff0c;但可以分享聚合计算后的结果。 联…

深入解析:深入理解 Docker:从入门到实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

⸢ 陆 ⸥ ⤳ 可信纵深防御:整体架构 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

wordpress站点取名做改网站

目录 一、涉及到的知识点 1.栈定义 2.Stack类 二、 使用Stack<T>类进行堆栈设计 1.创建一个新的Stack实例 2.然后&#xff0c;可以使用Push方法将元素添加到堆栈中 3.使用Pop方法从栈顶删除一个元素 4.使用Peek方法查看堆栈顶部的元素 三、实例 一、涉及到的知识…

从中序与后序遍历序列构建二叉树的迭代解法

如题,在今天刷题时碰到了这样一道二叉树的题目,原题地址在这里: https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal?envType=study-plan-v2&envId=top-interview-150…

(基于江协科技)51单片机入门:1.LED - 指南

(基于江协科技)51单片机入门:1.LED - 指南2025-09-27 20:44 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: blo…

安装 HuggingFace datasets 模块、包、库

HuggingFace datasets 是一个轻量级的数据集框架,用于数据集的加载、保存、预处理等。 pip install datasetsSuccessfully installed aiohttp-3.8.6 aiosignal-1.3.1 async-timeout-4.0.3 asynctest-0.13.0 attrs-24.…

WPF draw triangle and add contextmenu, menuitem programmatically

private void DrawTriangleInCanvas(){try{triangle = new Polygon(){Stroke = Brushes.Black,StrokeThickness = 3,Fill = Brushes.Red};double height = (Math.Sqrt(3) / 2) * sideLength;Point centerPt = new Poin…