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

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

独立观察员 2023 年 4 月 27 日

a4d4ec34f4b87c00dcffad0283ce2916.png

一、路由事件

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

定义事件:

ed2ac219b042d0611324a6a2026f6e1f.png

方法一、使用后台事件

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

07772f5c6821dc5db9444b0412ad3b4b.png

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

b7c9af9bc47177d133eec206de7c5aca.png

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

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

d27dee7b3a325f4376215f045a705bfd.png

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

d7bc6cb78701a5c2fa5d6e695fed5dbd.png

二、附加事件

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
}

图示:

78cafa33378b6e14c7d066d6ed97e148.png

2.2、绑定处理程序

0d6c75d0a7c4d3db33433a84ba660d29.png

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

2.3、触发事件

触发方法和普通路由事件相同,传递的参数也是到 OriginalSource 中去的:

f40fbb3338a9d3b17051d9988a7f68fe.png

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

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

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

三、资源

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

35df9f07eb17bf9feebb9c3489390c85.png

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

579d1b2630fdb95afa67e9e1d794dd73.png

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

800ff99b828d9ea2271ec4fb7a0b9d52.png

如下图所示:

542acb0c699c9fdb6787b3c6de50eb66.png

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

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

参考文章:

[官方文档] 路由事件概述(https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/events/routed-events-overview)

[官方文档] 如何创建自定义路由事件(https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/events/how-to-create-a-custom-routed-event)

[官方文档] 附加事件概述(https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/events/attached-events-overview)

-

技术群:添加小编微信并备注进群

小编微信:mm1552923   

公众号:dotNet编程大全    

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF中,自定义路由事件可以通过以下步骤实现: 1. 定义一个自定义路由事件: ``` public class MyRoutedEvent : RoutedEventArgs { public MyRoutedEvent() : base() { } public MyRoutedEvent(RoutedEvent routedEvent) : base(routedEvent) { } public MyRoutedEvent(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public string MyEventArgs { get; set; } // 自定义事件参数 public static readonly RoutedEvent MyEvent = EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyRoutedEvent)); // 添加路由事件处理程序 public event RoutedEventHandler MyEventHandler { add { AddHandler(MyEvent, value); } remove { RemoveHandler(MyEvent, value); } } // 触发路由事件 public void RaiseMyEvent() { RaiseEvent(new RoutedEventArgs(MyEvent)); } } ``` 在这个例子中,我们定义了一个继承自RoutedEventArgs的类,并添加了一个自定义事件参数MyEventArgs。我们还定义了一个静态只读的MyEvent路由事件,并为它添加了一个路由事件处理程序MyEventHandler。最后,我们实现了一个RaiseMyEvent方法,该方法将触发MyEvent路由事件。 2. 在UI元素中使用自定义路由事件: ``` <Button Content="Click me" Click="Button_Click"/> ``` 在这个例子中,我们将按钮的Click事件绑定到Button_Click方法。在该方法中,我们可以创建一个MyRoutedEvent实例并触发它: ``` private void Button_Click(object sender, RoutedEventArgs e) { MyRoutedEvent myEvent = new MyRoutedEvent(); myEvent.MyEventArgs = "Hello World!"; RaiseEvent(myEvent); } ``` 在这个例子中,我们创建了一个MyRoutedEvent实例,并将MyEventArgs设置为“Hello World!”。然后,我们调用RaiseEvent方法触发MyEvent路由事件。 3. 在父控件中处理自定义路由事件: ``` <Grid local:MyRoutedEvent.MyEvent="Grid_MyEvent"> <!-- 子控件 --> </Grid> ``` 在这个例子中,我们将Grid控件的MyEvent路由事件绑定到Grid_MyEvent方法。在该方法中,我们可以获取到MyEventArgs的值: ``` private void Grid_MyEvent(object sender, RoutedEventArgs e) { MyRoutedEvent myEvent = (MyRoutedEvent)e; string myEventArgs = myEvent.MyEventArgs; // 处理自定义路由事件 } ``` 在这个例子中,我们获取MyRoutedEvent实例,并将其转换为MyRoutedEvent类型。然后,我们可以获取MyEventArgs的值并进行处理。 这就是一个简单的自定义路由事件的实现方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值