说明:本系列基本上是《WPF揭秘》的读书笔记。在结构安排与文章内容上参照《WPF揭秘》的编排,对内容进行了总结并加入一些个人理解。

路由事件是专门设计用于在元素树中使用的事件。当路由事件触发后,其可以向上或向下遍历可视树和逻辑树,并且持续在每个元素上触发。

我们以按钮为例,说明路由事件的作用。在WPF之前的Windows客户端技术WinForm中按钮仅仅就是一个System.Windows.Forms命名空间下的Button类的对象。对其的点击等操作可以直接捕获,但是WPF中展现给你的按钮的组成可能会很复杂。其可能包括ButtonChrome或者TextBlock等可视子元素或者包含Rectangle等逻辑子元素,这时候对一个按钮的点击(MouseLeftButtonDown事件或KeyDown事件)可能实际发生在其可视子元素或逻辑子元素上,这时使用路由事件,由于其遍历可视树/逻辑树,Button的Click(路由)事件最终会被触发。

路由事件的实现

同依赖属性,路由事件也只有XAML语言天生支持,在传统过程式代码中注册路由事件的代码如下(以Button的Click路由事件为例)。首先注意的是,路由事件的约定名称是在传统事件名称的后面加上Event后缀(类似依赖属性的Property后缀)。

示例代码:

//声明路由事件
public static readonly RoutedEvent ClickEvent;

首先在Button类中声明这个路由事件。接着,

//注册路由事件
Button.ClickEvent = EventManager.RegisterRoutedEvent(
"Click",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(Button)
);

在Button类的静态构造函数中初始化这个路由事件。

最后添加可选的.NET事件包装器

//(可选).NET事件包装器
public event RoutedEventHandler Click
{add {   AddHandler(Button.ClickEvent, value); }remove {   RemoveHandler(Button.ClickEvent, value); }
}

触发路由事件的代码(可以位于OnMouseLeftButtonDown处理程序中)

RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));

分析:

RegisterRoutedEvent方法中传入的第一个参数定义了一个普通的.NET事件,事件包装器对这个事件进行包装。这样可以使过程式代码中事件使用更接近原有模式,并且XAML中也可以更方便的添加事件处理程序。

.NET事件包装器与内部实现

事件包装器内部调用的AddHandler与RemoveHandler方法位于继承自DependencyObject对象的UIElement对象。这两个方法分别可以向一个适当的路由事件添加一个委托对象及由路由事件移除一个委托对象。事件包装器中只能调用AddHandler和RemoveHandler,不能做它用,这点与属性包装器类似。

路由策略

在前文注册路由事件的代码中你已经见过RoutingStrategy这个枚举。与此相关的就是路由策略的概念,路由策略指的是事件触发遍历元素树的方式。有以下三种:

  • Tunneling(管道传递)

    事件首先在根元素上被触发,然后向下沿着树中每一个元素传递,直到到达源元素为止(或者直到处理程序把事件标记为已处理为止)。

  • Bubbling(冒泡传递)

    事件首先在源元素上被触发,然后向上沿着树中每一个元素传递,直到到达根元素为止(或者直到处理程序把事件标记为已处理为止)。

  • Direct(直接)

    事件仅在源元素上触发。这与普通.NET事件的行为基本相同。不同之处在于此类事件仍会参与事件触发器等路由事件的特定机制。

路由事件处理程序

路由事件处理程序(RoutedEventHandler)与普通的.NET事件的处理程序的设计遵循相同的模式:第一个参数为名为Sender的System.Object对象表示流处理程序被添加到的元素。第二个元素是名为e(通常习惯)的派生自RoutedEventArgs或其子类(这些类都派生自System.EventArgs类)的对象。这个对象有4个属性,通过它们变向扩展了提供给路由事件的参数。

  • Source:逻辑树中第一个触发该事件的元素。

  • OriginalSource:可视树中第一个触发该事件的元素(如点击Button首先触发的可视树为ButtonChrome,这个及前者的属性多用于区分鼠标事件之类的物理事件)。

  • Handled:布尔值,设置为true来标记事件为已处理,用于停止Tunneling或Bubbling事件在树上的触发。

  • RoutedEvent:真正的路由事件对象(如Button.ClickEvent),当多个路由事件共享一个事件处理函数时,此属性可以用来区分这个事件。

路由事件的作用

路由事件定义于UIElement类中,主要用于键盘,鼠标,触控笔之类触发的物理事件。而且这些路由事件往往是成对定义的即对于一个物理事件存在一个管道事件与一个冒泡事件相对应。其中管道事件的惯例是以Preview前缀开头。这个管道事件会在对应的冒泡事件之前触发,WPF的内部元素也只会响应冒泡事件。所以你可以在管道事件发生的过程中预览事件或者采取停止事件等措施。(实例:对于TextBox可以处理其KeyDown的管道事件(PreviewKeyDown事件)来严格限制其中输入的内容)。如果内容不合要求则在PreviewKeyDown事件发生的过程中标记事件为已处理,这样KeyDown冒泡事件将不再触发,则对TextBox的操作不会有任何效果。

注意在冒泡事件由source逐级向声明其的对象触发的过程中,可以被其中的接受事件的对象处理,并终止此冒泡事件。

最佳控制事件的方式

在路由事件的Preview版本中添加事件处理程序。

路由事件(管道或冒泡)的终止都是表面的,其只是被标记为已处理,但事件传递会继续,只是事件处理程序只处理没有标记为已处理的事件。

路由事件既可以沿可视树传递,也可以沿逻辑树传递。

附加事件

当树中(逻辑树或可视树)的每个元素都有路由事件时,路由事件(管道类型与冒泡类型)自然可以在其中传递。有了附加事件,事件传递也可以在一个没有定义这些事件的元素上进行。由于定义附加事件的元素本身不支持此事件,所以要在此附加事件上定义处理此事件(路由事件)的方法的名称。

示例:如下XAML代码将ListBox的SelectionChanged路由事件与Button的Click路由事件作为附加事件提供给window元素。

<Window ...ListBox.SelectionChanged="ListBox_SelectionChanged" Button.Click="Button_Click">

与这些XAML对应的过程代码实现:

this.AddHandler(ListBox.SelectionChangedEvent, new SelectionChangedEventHandler(ListBox_SelectionChanged));
this.AddHandler(Button.ClickEvent, new RoutedEventHandler(Button_Click));

需要注意的是这些过程代码应置于InitializeComponent()后。

本文完

参考:

《WPF揭秘》

转载于:https://www.cnblogs.com/lsxqw2004/archive/2011/09/08/4554476.html

WPF,Silverlight与XAML读书笔记第八 - WPF新概念之三路由事件相关推荐

  1. WPF,Silverlight与XAML读书笔记第六 - WPF新概念之一逻辑树与可视树

    说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. WPF中,XAML来呈现用户界面,其层次化的 ...

  2. WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形

    原文:WPF,Silverlight与XAML读书笔记第三十九 - 可视化效果之3D图形 说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘> ...

  3. WPF,Silverlight与XAML读书笔记第三十七 - 可视化效果之Brush

    说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. Brush用于定义形状的填充,包括前景色与背 ...

  4. ECMA-335(CLI)标准 读书笔记(第一部:概念和架构 第7章)

    上一篇:ECMA-335(CLI)标准 读书笔记(第一部:概念和架构 1~6章) 7.       CLS 7.1   介绍 CLS是一套倾向于提高语言互操作性的一套规则.我们应当遵循这些规则.11章 ...

  5. 计算机图形学 读书笔记(八) 光线跟踪加速Ray Tracing Acceleration

    写个读书笔记,一来作为字典以后可以查,二来记录自己的理解. 并没有对每个知识点的详细解释,大部分只有主观的定性的解释. 光线跟踪受到的限制: 1.时间复杂度和空间复杂度都很高. 2.主要时间用在了可见 ...

  6. 《深入浅出DPDK》读书笔记(八):网卡性能优化(异步中断模式、轮询模式、混和中断轮询模式)

    本文内容为读书笔记,摘自<深入浅出DPDK> 82.DPDK的轮询模式 <DPDK PMD( Poll Mode Driver)轮询模式驱动程序> DPDK采用了轮询或者轮询混 ...

  7. 《勋伯格和声学》读书笔记(八):转调

    前言 本文包含<勋伯格和声学>第六章--转调的相关读书笔记.如果说上一篇文章中所讨论的终止式的目的是明确一个调性,将有可能与相邻调式产生混淆的其他可能调式排除在外,那么转调的过程就需要首先 ...

  8. 读书笔记(八)--货币战争 金权天下

    ITFriend-IT从业者互动交流平台 http://www.itfriend.cn/ 读书笔记--第8篇--<货币战争&金权天下> 1.实力决定心态,心态决定视野,视野决定战略 ...

  9. 读书笔记(八)--货币战争金权天下

    ITFriend-IT从业者互动交流平台 http://www.itfriend.cn/ 读书笔记--第8篇--<货币战争&金权天下>   1.实力决定心态,心态决定视野,视野决定 ...

最新文章

  1. DzzOffice1.0 Beta2发布
  2. vscode 免费视频教程
  3. Nginx代理功能与负载均衡详解
  4. Sys和system用户、sysdba 和sysoper系统权限、dba角色的区别
  5. jdk8永久代从方法区移除的验证
  6. 使用静态代理模式实现公用的报表导出功能
  7. linux CentOS7最小化安装环境静默安装Oracle11GR2数据库(静默创建实例_08)
  8. wps分享为什么要登入_[win]为什么你需要便携应用?portableapps让你得心应手.
  9. MySQL DML语言笔记
  10. linux7ip路由,Centos7源地址访问路由(双IP双网关配置)
  11. 稳健估计,P范数最小法
  12. linux快速安装mysql教程
  13. c语言 api接口测试工具,Restlet Client插件
  14. LabWindows/CVI入门之第一章:LabWindows/CVI开发环境
  15. Hulu是什么?中国也有了?
  16. 你所不知道的良心网站第三弹
  17. 分布式系统技术难题--异地多活
  18. 2020-12-15
  19. 求任意两个整数的最大公因数
  20. 亿级流量电商详情页系统的大型高并发与高可用缓存架构实战 目录

热门文章

  1. 神经网络基础_反向传播_证明
  2. 数理统计-5.1 总体与样本
  3. ROS初学笔记 - C++11与PCL库冲突问题
  4. oracle em 界面乱码,oracle em 按钮乱码解决办法及em网页变成英文
  5. 审计日志删除 oracle,oracle audit,怎么审计ORACLE日志
  6. php mdecrypt generic,mdecrypt_generic
  7. MySQL 命令大全 - 命令详解
  8. 什么是JAVA内容仓库(Java Content Repository)
  9. MySQL技术内幕读书笔记(一)——Mysql体系结构和存储引擎
  10. Python3文件操作详解 Python3文件操作大全