WPF 路由事件和附加事件简明教程

WPF 路由事件和附加事件简明教程

WPF 路由事件和附加事件简明教程

独立观察员 2023 年 4 月 27 日

一、路由事件

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、使用示例

定义事件:

WPF 路由事件和附加事件简明教程

 

方法一、使用后台事件

此事件定义在窗口后台类中,在前台使用时还是需要使用完全限定名:

WPF 路由事件和附加事件简明教程

 

引发事件时将数据类传进去了,用处理方法的 e.OriginalSource 就能取到了:

WPF 路由事件和附加事件简明教程

 

方法二、使用事件转命令绑定

EventName 仅需要事件名称即可,不需要完全限定名了;绑定命令,EventArgsParameterPath 设置为 “OriginalSource”,这样就能获取到对应的参数了:

WPF 路由事件和附加事件简明教程

 

命令定义及处理方法中都指定了对应类型的参数:

WPF 路由事件和附加事件简明教程

 

二、附加事件

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
}

 

图示:

WPF 路由事件和附加事件简明教程

 

2.2、绑定处理程序

WPF 路由事件和附加事件简明教程

 

和普通路由事件同理,可以使用代码隐藏页的方法绑定处理方法,也可以使用事件转命令方式绑定。

 

======↓↓↓ 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 

WPF 路由事件和附加事件简明教程

 

使用方法:

<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 中去的:

WPF 路由事件和附加事件简明教程

 

注意:以下两段未严谨验证,仅依据现有知识和实际现象推断,大家自行把握。

和普通路由事件触发的不同之处在于,前面需要指定触发源元素对象,不然可能会进不了事件处理方法。原因应该是这样的,由于事件定义为了冒泡事件,所以是从内层元素向外层传递的,所以如果处理方法写在事件触发元素的内层或同一层 (上图中如果不写 tb 就是同一层了),那么处理方法就接受不到消息了。

所以可以总结一下,附加事件是一种定义的时候写法特殊一些的路由事件,可定义在普通类中。触发事件和接收事件时使用完全限定名,且两者都不限制是在哪个 UI 元素上,不过需要依据事件的类型(冒泡还是隧道)来合理安排两者分别放置在什么层级的元素上,具体来说就是,如果是冒泡事件则触发元素在接收元素内层,如果是隧道事件则触发元素在接收元素外层。可以看出,使用路由事件的好处之一就是可灵活放置接收处理消息方法的位置。

 

三、资源

官方对于依赖属性(propdp)和附加属性(propa)都提供了代码片段,使用方法就是输入对应的快捷键后按一次或两次 Tab,就能插入了;或者在代码编辑窗口,按 Ctrl K X 进行选择:

WPF 路由事件和附加事件简明教程

 

但是对于路由事件、附加事件等,官方好像没有提供代码片段,只能自己生成了,推荐使用 Code Snippest Studio 扩展插件来生成:

WPF 路由事件和附加事件简明教程

 

生成的代码片段文件后缀为 .snippet,保存到某个文件夹后,打开 VS–> 工具 –> 代码片段管理器,添加上这个文件夹即可使用了:

WPF 路由事件和附加事件简明教程

 

如下图所示:

WPF 路由事件和附加事件简明教程

 

本次主要生成了 路由事件(wpfre)、附加事件(wpfae),还附赠改进的代码片段 依赖属性(wpfdp)、附加属性(wpfap),以及某种情况下适用的 通知属性(wpfp)。

好消息是,本人已将这些代码片段打包上传到百度云盘了,下载地址可在微信公众号 “独立观察员博客(DLGCY_BLOG)” 消息框回复 “代码片段” 获取。

 

参考文章:

[官方文档] 路由事件概述 

[官方文档] 如何创建自定义路由事件 

[官方文档] 附加事件概述

 

 

原创文章,转载请注明: 转载自 独立观察员(dlgcy.com)

本文链接地址: [WPF 路由事件和附加事件简明教程](https://dlgcy.com/wpf-routed-event-and-attached-event/)

关注微信公众号 独立观察员博客(DLGCY_BLOG) 第一时间获取最新文章

%title插图%num

发表评论