WPF 路由事件和附加事件简明教程
一、路由事件
1.1、定义
概括:可在 WPF 元素树中传递的事件,支持界面绑定处理方法。
代码:
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(OwnerType)); /// <summary> /// [路由事件]注释 /// </summary> public event RoutedEventHandler Tap { add => AddHandler(TapEvent, value); remove => RemoveHandler(TapEvent, value); } /// <summary> /// 路由事件 注释 的触发方法 /// </summary> /// <param name="originalSource">此参数会传递到事件参数的 OriginalSource 属性中</param> private void RaiseTapEvent(object originalSource = null) { RaiseEvent(new RoutedEventArgs(RangeSelectedEvent, originalSource)); }
1.2、使用示例
定义事件:
方法一、使用后台事件
此事件定义在窗口后台类中,在前台使用时还是需要使用完全限定名:
引发事件时将数据类传进去了,用处理方法的 e.OriginalSource 就能取到了:
方法二、使用事件转命令绑定
EventName 仅需要事件名称即可,不需要完全限定名了;绑定命令,EventArgsParameterPath 设置为 “OriginalSource”,这样就能获取到对应的参数了:
命令定义及处理方法中都指定了对应类型的参数:
二、附加事件
2.1、定义
概括:可在普通类(非 UIElement 子类)中定义的路由事件。
代码:
public class AttachedEventHelper { #region 附加事件 public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AutoTableEventHelper)); public static void AddValueChangedHandler(DependencyObject dependencyObject, RoutedEventHandler handler) { if (dependencyObject is not UIElement uiElement) return; uiElement.AddHandler(ValueChangedEvent, handler); } public static void RemoveValueChangedHandler(DependencyObject dependencyObject, RoutedEventHandler handler) { if (dependencyObject is not UIElement uiElement) return; uiElement.RemoveHandler(ValueChangedEvent, handler); } #endregion }
图示:
2.2、绑定处理程序
和普通路由事件同理,可以使用代码隐藏页的方法绑定处理方法,也可以使用事件转命令方式绑定。
======↓↓↓ 2023 年 5 月 15 日 更新 ↓↓↓======
WPF 的行为包的 EventTrigger 只提供了 EventName 属性,适用于元素的普通事件,上面也展示了能勉强适用于路由事件,但是对于附加事件就无能为力了。
找到了文章《How to attached an MVVM EventToCommand to an Attached event》提供了一个自定义的 RoutedEventTrigger 类(基于 EventTriggerBase),提供了 RoutedEvent 属性,能够指定附加事件,这样我们就能够将附加事件转为命令了。
本人已将代码托管到:https://gitee.com/dlgcy/WPFTemplateLib/blob/master/EventTriggers/RoutedEventTrigger.cs
使用方法:
<b:Interaction.Triggers> <helpers:RoutedEventTrigger RoutedEvent="local:YourAttachedEventHelper.YourAttachedEvent"> <b:InvokeCommandAction Command="{Binding YourCmd}" EventArgsParameterPath="OriginalSource"/> </helpers:RoutedEventTrigger> </b:Interaction.Triggers>
======↑↑↑ 2023 年 5 月 15 日 更新 ↑↑↑======
2.3、触发事件
触发方法和普通路由事件相同,传递的参数也是到 OriginalSource 中去的:
注意:以下两段未严谨验证,仅依据现有知识和实际现象推断,大家自行把握。
和普通路由事件触发的不同之处在于,前面需要指定触发源元素对象,不然可能会进不了事件处理方法。原因应该是这样的,由于事件定义为了冒泡事件,所以是从内层元素向外层传递的,所以如果处理方法写在事件触发元素的内层或同一层 (上图中如果不写 tb 就是同一层了),那么处理方法就接受不到消息了。
所以可以总结一下,附加事件是一种定义的时候写法特殊一些的路由事件,可定义在普通类中。触发事件和接收事件时使用完全限定名,且两者都不限制是在哪个 UI 元素上,不过需要依据事件的类型(冒泡还是隧道)来合理安排两者分别放置在什么层级的元素上,具体来说就是,如果是冒泡事件则触发元素在接收元素内层,如果是隧道事件则触发元素在接收元素外层。可以看出,使用路由事件的好处之一就是可灵活放置接收处理消息方法的位置。
三、资源
官方对于依赖属性(propdp)和附加属性(propa)都提供了代码片段,使用方法就是输入对应的快捷键后按一次或两次 Tab,就能插入了;或者在代码编辑窗口,按 Ctrl K X 进行选择:
但是对于路由事件、附加事件等,官方好像没有提供代码片段,只能自己生成了,推荐使用 Code Snippest Studio 扩展插件来生成:
生成的代码片段文件后缀为 .snippet,保存到某个文件夹后,打开 VS–> 工具 –> 代码片段管理器,添加上这个文件夹即可使用了:
如下图所示:
本次主要生成了 路由事件(wpfre)、附加事件(wpfae),还附赠改进的代码片段 依赖属性(wpfdp)、附加属性(wpfap),以及某种情况下适用的 通知属性(wpfp)。
好消息是,本人已将这些代码片段打包上传到百度云盘了,下载地址可在微信公众号 “独立观察员博客(DLGCY_BLOG)” 消息框回复 “代码片段” 获取。
参考文章:
原创文章,转载请注明: 转载自 独立观察员(dlgcy.com)
本文链接地址: [WPF 路由事件和附加事件简明教程](https://dlgcy.com/wpf-routed-event-and-attached-event/)
关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章
发表评论