【WPF.NET开发】将路由事件标记为已处理和类处理
本文内容
- 先决条件
- 何时将路由事件标记为已处理
- 预览和浮升路由事件对
- 实例和类路由事件处理程序
- 复合控件中的输入事件禁止
尽管对于何时将路由事件标记为已处理没有绝对规则,但如果代码以重要方式响应事件,请考虑将事件标记为已处理。 标记为已处理的路由事件会继续进行其路由,但只会调用配置为响应已处理事件的处理程序。 基本上,将路由事件标记为已处理会限制其在事件路由上对侦听器的可见性。
路由事件处理程序可以是实例处理程序或类处理程序。 实例处理程序处理对象或 XAML 元素上的路由事件。 类处理程序在类级别处理路由事件,会在任何实例处理程序对类的任何实例响应相同事件之前进行调用。 当路由事件标记为已处理时,它们通常会在类处理程序中标记为这样。 本文讨论了将路由事件标记为已处理的好处和潜在缺陷、不同类型的路由事件和路由事件处理程序以及复合控件中的事件禁止。
1、先决条件
本文假定你对路由事件有基本的了解,并且已阅读路由事件概述
。 若要遵循本文中的示例,如果熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 Windows Presentation Foundation (WPF) 应用程序,将会很有帮助。
2、何时将路由事件标记为已处理
通常,只应有一个处理程序为每个路由事件提供重要响应。 避免使用路由事件系统跨多个处理程序提供重要响应。 构成重要响应的定义是主观的,取决于应用程序。 一般准则是:
- 重要响应包括设置焦点、修改公共状态、设置影响视觉表示形式的属性、引发新事件以及完全处理事件。
- 不重要响应包括修改私有状态(而没有视觉或编程影响)、事件日志记录以及检查事件数据而不响应事件。
某些 WPF 控件通过将不需要进一步处理的组件级别事件标记为已处理来禁止这些事件。
若要将事件标记为已处理,请在其事件数据中将 Handled 属性值设置为 true
。 尽管可以将该值还原到 false
,但很少需要这样做。
3、预览和浮升路由事件对
预览和浮升路由事件对特定于输入事件
。 多个输入事件实现隧道和浮升路由事件对,例如 PreviewKeyDown 和 KeyDown。 Preview
前缀表示一旦预览事件完成,浮升事件便会启动。 每个预览和浮升事件对会共享事件数据的相同实例。
路由事件处理程序按对应于事件路由策略的顺序进行调用:
- 预览事件从应用程序根元素向下传递到引发路由事件的元素。 附加到应用程序根元素的预览事件处理程序会首先进行调用,接下来是附加到后续嵌套元素的处理程序。
- 预览事件完成后,配对的浮升事件会从将路由事件引发的元素传递到应用程序根元素。 附加到引发路由事件的相同元素的浮升事件处理程序会首先进行调用,接下来是附加到后续父元素的处理程序。
配对的预览和浮升事件是声明并引发自身路由事件的多个 WPF 类的内部实现的一部分。 如果没有该类级别内部实现,预览和浮升路由事件会完全独立,不会共享事件数据(无论事件命名如何)。
由于每个预览和浮升事件对共享事件数据的相同实例,因此如果预览路由事件标记为已处理,则其配对的浮升事件也会进行处理。 如果浮升路由事件标记为已处理,则不会影响配对的预览事件,因为预览事件已完成。 将预览和浮升输入事件对标记为已处理时要小心。 已处理的预览输入事件不会为隧道路由的其余部分调用任何正常注册的事件处理程序,并且不会引发配对的浮升事件。 已处理的浮升输入事件不会为浮升路由的其余部分调用任何正常注册的事件处理程序。
4、实例和类路由事件处理程序
路由事件处理程序可以是实例处理程序或类处理程序。 给定类的类处理程序会在任何实例处理程序对该类的任何实例响应相同事件之前进行调用。 由于此行为,当路由事件标记为已处理时,它们通常会在类处理程序中标记为这样。 有两种类型的类处理程序:
静态类事件处理程序,通过在静态类构造函数中调用 RegisterClassHandler 方法进行注册。
重写类事件处理程序,通过重写基类虚拟事件方法进行注册。 基类虚拟事件方法的存在主要是用于输入事件,名称以 On<事件名称> 和 OnPreview<事件名称> 开头。
4.1 实例事件处理程序
可以通过直接调用 AddHandler 方法,将实例处理程序附加到对象或 XAML 元素。 WPF 路由事件实现使用 AddHandler
方法附加事件处理程序的公共语言运行时 (CLR) 事件包装器。 由于用于附加事件处理程序的 XAML 特性语法会导致调用 CLR 事件包装器,因此即时是在 XAML 中附加处理程序也会解析为 AddHandler
调用。 对于已处理的事件:
- 不会调用使用 XAML 特性语法或
AddHandler
的公共签名附加的处理程序。 - 会调用在
handledEventsToo
参数设置为true
的情况下使用 AddHandler(RoutedEvent, Delegate, Boolean) 重载附加的处理程序。 此重载适用于需要响应已处理的事件的极少数情况。 例如,元素树中的某个元素已将事件标记为已处理,但事件路由中的其他元素需要响应已处理的事件。
下面的 XAML 示例将名为 componentWrapper
的自定义控件(包装名为 componentTextBox
的 TextBox)添加到名为 outerStackPanel
的 StackPanel。 PreviewKeyDown 事件的实例事件处理程序使用 XAML 特性语法附加到 componentWrapper
。 因此,实例处理程序只会响应由 componentTextBox
引发的未经处理的 PreviewKeyDown
隧道事件。
<StackPanel Name="outerStackPanel" VerticalAlignment="Center"><custom:ComponentWrapperx:Name="componentWrapper"TextBox.PreviewKeyDown="HandlerInstanceEventInfo"HorizontalAlignment="Center"><TextBox Name="componentTextBox" Width="200" /></custom:ComponentWrapper>
</StackPanel>
MainWindow
构造函数使用 UIElement.AddHandler(RoutedEvent, Delegate, Boolean) 重载(handledEventsToo
参数设置为 true
)将 KeyDown
浮升事件的实例处理程序附加到 componentWrapper
。 因此,实例事件处理程序会响应未经处理和已处理的事件。
public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();// Attach an instance handler on componentWrapper that will be invoked by handled KeyDown events.componentWrapper.AddHandler(KeyDownEvent, new RoutedEventHandler(Handler.InstanceEventInfo),handledEventsToo: true);}// The handler attached to componentWrapper in XAML.public void HandlerInstanceEventInfo(object sender, KeyEventArgs e) => Handler.InstanceEventInfo(sender, e);
}
下一部分显示了 ComponentWrapper
的代码隐藏实现。
4.2 静态类事件处理程序
可以通过在类的静态构造函数中调用 RegisterClassHandler 方法来附加静态类事件处理程序。 类层次结构中的每个类都可以为每个路由事件注册其自己的静态类处理程序。 因此,可以在事件路由中的任何给定节点上为相同事件调用多个静态类处理程序。 构造事件的事件路由时,每个节点的所有静态类处理程序都会添加到事件路由中。 节点上静态类处理程序的调用顺序从派生程度最高的静态类处理程序开始,接下来是来自每个后续基类的静态类处理程序。
使用 RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) 重载(handledEventsToo
参数设置为 true
)注册的静态类事件处理程序会响应未经处理和已处理的路由事件。
静态类处理程序通常注册为仅响应未经处理的事件。 在这种情况下,如果节点上的派生类处理程序将事件标记为已处理,则不会调用该事件的基类处理程序。 在这种情况下,基类处理程序实际上会被派生类处理程序所替换。 基类处理程序通常在视觉外观、状态逻辑、输入处理和命令处理等领域中帮助控制设计,因此在替换它们时要谨慎。 不将事件标记为已处理的派生类处理程序最终会补充基类处理程序,而不是替换它们。
下面的代码示例演示在前面 XAML 中引用的 ComponentWrapper
自定义控件的类层次结构。 ComponentWrapper
类从 ComponentWrapperBase
派生类,而后者又从 StackPanel 类派生。 在 ComponentWrapper
和 ComponentWrapperBase
类的静态构造函数中使用的 RegisterClassHandler
方法会为其中每个类注册静态类事件处理程序。 WPF 事件系统在 ComponentWrapperBase
静态类处理程序之前调用 ComponentWrapper
静态类处理程序。
public class ComponentWrapper : ComponentWrapperBase
{static ComponentWrapper(){// Class event handler implemented in the static constructor.EventManager.RegisterClassHandler(typeof(ComponentWrapper), KeyDownEvent, new RoutedEventHandler(Handler.ClassEventInfo_Static));}// Class event handler that overrides a base class virtual method.protected override void OnKeyDown(KeyEventArgs e){Handler.ClassEventInfo_Override(this, e);// Call the base OnKeyDown implementation on ComponentWrapperBase.base.OnKeyDown(e);}
}public class ComponentWrapperBase : StackPanel
{// Class event handler implemented in the static constructor.static ComponentWrapperBase(){EventManager.RegisterClassHandler(typeof(ComponentWrapperBase), KeyDownEvent, new RoutedEventHandler(Handler.ClassEventInfoBase_Static));}// Class event handler that overrides a base class virtual method.protected override void OnKeyDown(KeyEventArgs e){Handler.ClassEventInfoBase_Override(this, e);e.Handled = true;Debug.WriteLine("The KeyDown routed event is marked as handled.");// Call the base OnKeyDown implementation on StackPanel.base.OnKeyDown(e);}
}
下一部分会讨论此代码示例中的重写类事件处理程序的代码隐藏实现。
4.3 重写类事件处理程序
某些视觉元素基类会为其每个公共路由输入事件公开空的 <On>事件名称 和 <OnPreview>事件名称 虚拟方法。 例如,UIElement 会实现 OnKeyDown 和 OnPreviewKeyDown 虚拟事件处理程序以及许多其他事件处理程序。 可以重写基类虚拟事件处理程序,以便为派生类实现重写类事件处理程序。 例如,可以通过重写 OnDragEnter 虚拟方法,为任何 UIElement
派生类中的 DragEnter 事件添加重写类处理程序。 重写基类虚拟方法是比在静态构造函数中注册类处理程序更简单的一种实现类处理程序的方法。 在重写中,可以引发事件、启动特定于类的逻辑以更改实例中的元素属性、将事件标记为已处理或执行其他事件处理逻辑。
与静态类事件处理程序不同,WPF 事件系统仅为类层次结构中派生程度最高的类调用重写类事件处理程序。 类层次结构中派生程度最高的类随后可以使用 base 关键字调用虚拟方法的基实现。 在大多数情况下,无论是否将事件标记为已处理,都应调用基本实现。 如果类要求替换基实现(如果有),则应仅省略调用基实现。 在重写代码之前还是之后调用基实现取决于实现的性质。
在前面的代码示例中,基类 OnKeyDown
虚拟方法在 ComponentWrapper
和 ComponentWrapperBase
类中进行重写。 由于 WPF 事件系统仅调用 ComponentWrapper.OnKeyDown
重写类事件处理程序,因此该处理程序使用 base.OnKeyDown(e)
调用 ComponentWrapperBase.OnKeyDown
重写类事件处理程序,后者进而使用 base.OnKeyDown(e)
调用 StackPanel.OnKeyDown
虚拟方法。 前面的代码示例中的事件顺序为:
- 附加到
componentWrapper
的实例处理程序由PreviewKeyDown
路由事件触发。 - 附加到
componentWrapper
的静态类处理程序由KeyDown
路由事件触发。 - 附加到
componentWrapperBase
的静态类处理程序由KeyDown
路由事件触发。 - 附加到
componentWrapper
的重写类处理程序由KeyDown
路由事件触发。 - 附加到
componentWrapperBase
的重写类处理程序由KeyDown
路由事件触发。 KeyDown
路由事件标记为已处理。- 附加到
componentWrapper
的实例处理程序由KeyDown
路由事件触发。 处理程序已注册(handledEventsToo
参数设置为true
)。
5、复合控件中的输入事件禁止
某些复合控件会在组件级别禁止输入事件
,以便将它们替换为包含更多信息或暗示更特定行为的自定义高级事件。 按照定义,复合控件是由多个实际控件或控件基类组成的。 经典示例是将各种鼠标事件转换为 Click 路由事件的 Button 控件。 Button
基类是间接派生自 UIElement 的 ButtonBase 类。 控制输入处理所需的大部分事件基础结构在 UIElement
级别提供。 UIElement
会公开多个 Mouse 事件,例如 MouseLeftButtonDown 和 MouseRightButtonDown。 UIElement
还实现空虚拟方法 OnMouseLeftButtonDown 和 OnMouseRightButtonDown 作为预注册类处理程序。 ButtonBase
会重写这些类处理程序,在重写处理程序中将 Handled 属性设置 true
为并引发 Click
事件。 大多数侦听器的最终结果是 MouseLeftButtonDown
和 MouseRightButtonDown
事件会隐藏,而高级 Click
事件可见。
解决输入事件禁止问题
有时,各个控件内的事件禁止可能会干扰应用程序中的事件处理逻辑。 例如,如果应用程序使用 XAML 特性语法在 XAML 根元素上附加 MouseLeftButtonDown 事件的处理程序,则不会调用该处理程序,因为 Button 控件将 MouseLeftButtonDown
事件标记为已处理。 如果希望对已处理的路由事件调用应用程序的根的元素,则可以:
-
通过调用 UIElement.AddHandler(RoutedEvent, Delegate, Boolean) 方法(
handledEventsToo
参数设置为true
)来附加处理程序。 此方法需要在获取要附加到的元素的对象引用后,在代码隐藏中附加事件处理程序。 -
如果标记为已处理的事件是浮升输入事件,则附加配对的预览事件的处理程序(如果可用)。 例如,如果控件禁止了
MouseLeftButtonDown
事件,则可以改为附加 PreviewMouseLeftButtonDown 事件的处理程序。 此方法仅适用于共享事件数据的预览和浮升输入事件对。 请注意不要将PreviewMouseLeftButtonDown
标记为已处理,因为这会完全禁止 Click 事件。
相关文章:
【WPF.NET开发】将路由事件标记为已处理和类处理
本文内容 先决条件何时将路由事件标记为已处理预览和浮升路由事件对实例和类路由事件处理程序复合控件中的输入事件禁止 尽管对于何时将路由事件标记为已处理没有绝对规则,但如果代码以重要方式响应事件,请考虑将事件标记为已处理。 标记为已处理的路由…...

2023年03月18日_微软office365 copilot相关介绍
文章目录 Copilot In WordCopilot In PowerpointCopilot In ExcelCopilot In OutlookCopilot In TeamsBusiness Chat1 - copilot in word2 - copilot in excel3 - copilot in powerpoint4 - copilot in outlook5 - copilot in teams6 - business chat word 1、起草草稿 2、自动…...

GBASE南大通用携手宇信科技打造“一表通”全链路解决方案
什么是“一表通”? “一表通”是国家金融监督管理总局为发挥统计监督效能、完善银行保险监管统计制度、推进监管数据标准化建设、打破数据壁垒,而制定的新型监管数据统计规范。相较于以往的报送接口,“一表通”提高了对报送时效性、校验准确…...

Python 内置高阶函数练习(Leetcode500.键盘行)
Python 内置高阶函数练习(Leetcode500.键盘行) 【一】试题 (1)地址: 500. 键盘行 - 力扣(LeetCode) (2)题目 给你一个字符串数组 words ,只返回可以使用在…...

【JavaWeb】day01-HTMLCSS
day01-HTML&CSS HTML 图片标签:<img> src:指定图像URL(绝对路径/相对路径)width:图像宽度(像素/相对于父元素的百分比)height:图像高度(像素/相对于父元素的百…...

【工具】windeployqt 在windows + vscode环境下打包
目录 0.背景简介 1.windeployqt简介 2.打包具体过程 1)用vscode编译,生成Release文件夹(也有Debug文件夹,但是发布版本一般都是用Release) 2)此时可以看下Release文件夹内,一般是.exe可执行…...

跟着LearnOpenGL学习12--光照贴图
文章目录 一、前言二、漫反射贴图三、镜面光贴图3.1、采样镜面光贴图 一、前言 在跟着LearnOpenGL学习11–材质中,我们讨论了让每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观…...

DotNet 命令行开发
DotNet 命令行开发 下载安装下载 SDK安装 SDK绿色版下载绿化脚本 常用命令创建 dotnet new运行 dotnet run发布应用 dotnet publish更多命令 VSCode 调试所需插件调试 CS 配置项目.csproj排除依赖关系 launch.jsontasks.json 参考资料 下载安装 下载 SDK 我们就下最新的好&am…...

hyperf console 执行
一、原理描述 hyperf中,不难发现比如自定义控制器中获取参数,hyperf.php中容器获取,传入的都是接口,而不是实体类。 这是因为框架中的配置文件有设置对应抽象类的子类,框架加载的时候将其作为数组,使用的…...
第一篇 设计模式引论 - 探索软件设计的智慧结晶
1. 设计模式的定义和起源 设计模式,这个术语最初在建筑领域被广泛使用,用来描述在建筑设计中反复出现的问题及其解决方案。在软件工程中,设计模式同样指的是在软件设计过程中反复出现的、经过验证的最佳实践和解决方案。 1994年,…...
HBase基础知识(六):HBase 对接 Hive
1. HBase 与 Hive 的对比 1.Hive (1) 数据仓库 Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个双射关系,以 方便使用 HQL 去管理查询。 (2) 用于数据分析、清洗 Hive 适用于离线的数据分析和清洗,延迟较高。 (3) 基于…...
Java连接Mysql报错:javax.net.ssl.SSLException: Received fatal alert: internal_error
大致报错日志如下: The last packet successfully received from the server was 11 milliseconds ago. The last packet sent successfully to the server was 10 milliseconds ago.at sun.reflect.GeneratedConstructorAccessor275.newInstance(Unknown Source)…...

Mixtral 8*7B + Excel + Python 超强组合玩转数据分析
Mixtral 8*7B Excel Python 超强组合玩转数据分析 0. 背景1. 使用 Mixtral 8*7B pandas 实现数据导入和导出1.1 使用 Mixtral 8*7B pandas 导入 Excel 文件中的数据1.2 使用 Mixtral 8*7B pandas 导出 Excel 文件中的数据 2. 使用 Mixtral 8*7B pandas 实现单个文件数据的…...
深入浅出理解Web认证:Session、Cookie与Token
在Web开发的世界中,理解Session、Session ID、Cookie和Token之间的区别至关重要。实际上,这些概念并不复杂,只需几句话就能澄清它们的核心区别。 首先,我们需要区分Session和Session ID。Session实际上是存储在服务器端的数据&am…...

智慧零售技术探秘:关键技术与开源资源,助力智能化零售革新
智慧零售是一种基于先进技术的零售业态,通过整合物联网、大数据分析、人工智能等技术,实现零售过程的智能化管理并提升消费者体验。 实现智慧零售的关键技术包括商品的自动识别与分类、商品的自动结算等等。 为了实现商品的自动识别与分类,…...

2012年第一届数学建模国际赛小美赛B题大规模灭绝尚未到来解题全过程文档及程序
2012年第一届数学建模国际赛小美赛 B题 大规模灭绝尚未到来 原题再现: 亚马逊是地球上现存最大的雨林,比地球上任何地方都有更多的野生动物。它位于南美洲大陆的北侧,共有9个国家:巴西、玻利维亚、厄瓜多尔、秘鲁、哥伦比亚、委…...
macos管理本地golang的多版本sdk
背景 无论你是哪个编程语言的开发者,例如 Java、Go 等,通常在本地开发过程中,你经常需要安装相应的 SDK。由于各种原因,往往需要在不同的项目中来回切换多个版本的 SDK。 安装步骤 1.安装homebrew /bin/bash -c "$(curl -…...

count distinct在spark中的运行机制
文章目录 预备 数据和执行语句Expand第一次HashAggregateShuffle and Second HashAggregate最后结果性能原文 预备 数据和执行语句 SELECT COUNT(*), SUM(items), COUNT(DISTINCT product), COUNT(DISTINCT category) FROM orders;假设源数据分布在两个1核的结点上࿰…...

创建加密分区或者文件
文章目录 [GParted 中已清除的分区与未格式化的分区](https://superuser.com/questions/706624/cleared-vs-unformatted-partition-in-gparted)创建加密分区解密创建的加密分区以便挂载格式化设备未具体的格式(这里为ext4格式)创建挂载点目录挂载加密的文…...
STL——遍历算法
1.for_each 函数原型: for_each(iterator beg, iterator end, _func);——// 遍历算法 遍历容器元素; beg 开始迭代器;end 结束迭代器; _func 函数或者函数对象 #include<iostream> using namespace std; #include<ve…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...