有些 WPF 控件对某些路由事件具有固有的类处理。 类处理可能会提供路由事件从未引发过的外观,但实际上它被标记为由类处理程序处理。 如果需要事件处理程序来响应已处理的事件,可以将处理程序
handledEventsToo
注册为
true
设置为 。 有关详细信息,请参阅将
路由事件标记为已处理和类处理
。
XAML 语言还定义了一个名为附加事件的特殊类型的事件。 附加事件可用于在非元素类中定义新的
路由事件
,并在树中的任何元素上引发该事件。 为此,必须将附加事件注册为路由事件,并提供支持附加事件功能的特定
支持代码
。 由于附加事件注册为路由事件,因此在元素上引发时,它们会通过元素树传播。
<StackPanel Name="StackPanel1" Button.Click="Button_Click">
<Button>Click me</Button>
</StackPanel>
在示例中,将事件处理程序添加到的父元素侦听器是
StackPanel
。 但是,
Click
路由事件在 类上
ButtonBase
实现和引发,并通过继承提供给
Button
类。
Button
尽管 类“拥有”事件
Click
,但路由事件系统允许将任何路由事件的处理程序附加到任何
UIElement
或
ContentElement
实例侦听器,这些侦听器本来可以具有 CLR 事件的处理程序。 这些限定的事件属性名称的默认
xmlns
命名空间通常是默认的 WPF
xmlns
命名空间,但也可以为自定义路由事件指定带前缀的命名空间。 有关 的详细信息
xmlns
,请参阅
WPF XAML 的 XAML 命名空间和命名空间映射
。
WPF 平台中路由事件的一个频繁应用是
输入事件
。 按照约定,遵循隧道路由的 WPF 路由事件的名称以“预览”为前缀。 预览前缀表示预览事件在配对的浮升事件开始之前完成。 输入事件通常成对出现,一个是预览事件,另一个是冒泡路由事件。 例如,
PreviewKeyDown
和
KeyDown
。 事件对共享事件数据的同一实例,对于
PreviewKeyDown
和
KeyDown
的类型为
KeyEventArgs
。 有时,输入事件只有浮升版本,或者只有直接路由版本。 在 API 文档中,路由事件主题交叉引用路由事件对,并阐明每个路由事件的路由策略。
实现成对的 WPF 输入事件,以便来自输入设备的单个用户操作(如按鼠标按钮)将按顺序引发预览和冒泡路由事件。 首先,引发预览事件并完成其路由。 完成预览事件后,将引发浮升事件并完成其路由。
RaiseEvent
在引发浮升事件的实现类中调用的方法将重复用于冒泡事件的预览事件中的事件数据。
标记为已处理的预览输入事件不会为预览路由的其余部分调用任何正常注册的事件处理程序,并且不会引发配对的浮升事件。 此处理行为对于希望在其控件的顶层报告基于命中测试的输入事件或基于焦点的输入事件的组合控件设计器非常有用。 控件的顶级元素有机会对控件子组件中的预览事件进行类处理,以便用特定于控件的顶级事件“替换”它们。
为了说明输入事件处理的工作原理,请考虑以下输入事件示例。 在以下树图中,
leaf element #2
是 和
MouseDown
配对事件的源
PreviewMouseDown
:
在叶元素 #2 上执行鼠标按下操作后的事件处理顺序为:
PreviewMouseDown
根元素上的隧道事件。
PreviewMouseDown
中间元素 #1 上的隧道事件。
PreviewMouseDown
叶元素 #2(源元素)上的隧道事件。
MouseDown
叶元素 #2(源元素)上的浮升事件。
MouseDown
中间元素 #1 上的浮升事件。
MouseDown
根元素上的浮升事件。
路由事件处理程序委托提供对引发事件的对象和调用处理程序的对象的引用。 最初引发事件的对象由
Source
事件数据中的 属性报告。 调用处理程序的对象由
发送方
参数报告。 对于任何给定的路由事件实例,引发该事件的对象不会随着事件穿过元素树而更改,但
sender
会更改。 在上图的步骤 3 和 4 中,
Source
和
sender
是同一对象。
如果输入事件处理程序完成了处理事件所需的特定于应用程序的逻辑,则应将输入事件标记为已处理。 通常,一旦输入事件被标记为
Handled
,就不会调用沿事件路由进一步的处理程序。 但是,即使事件标记为已处理,也会调用向 设置为
true
的参数注册
handledEventsToo
的输入事件处理程序。 有关详细信息,请参阅
预览事件
和
将路由事件标记为已处理和类处理
。
预览和冒泡事件对的概念(共享事件数据以及依次引发预览事件和冒泡事件)仅适用于某些 WPF 输入事件,不适用于所有路由事件。 如果实现自己的输入事件来解决高级方案,请考虑遵循 WPF 输入事件对方法。
如果要实现自己的响应输入事件的复合控件,请考虑使用预览事件来抑制子组件上引发的输入事件,并将其替换为表示完整控件的顶级事件。 有关详细信息,请参阅
将路由事件标记为已处理和类处理
。
有关 WPF 输入系统以及典型应用程序方案中输入和事件如何交互的详细信息,请参阅
输入概述
。
EventSetter 和 EventTrigger
在标记样式中,可以使用 来包括预先声明的 XAML 事件处理语法
EventSetter
。 处理 XAML 时,引用的处理程序将添加到带样式的实例中。 只能为路由事件声明
EventSetter
。 在以下示例中,引用的
ApplyButtonStyle
事件处理程序方法在代码隐藏中实现。
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="ApplyButtonStyle"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Click="Button_Click">Click me</Button>
</StackPanel>
节点可能
Style
已包含与指定类型的控件相关的其他样式信息,并且使
EventSetter
成为这些样式的一部分会促进代码重用,即使在标记级别也是如此。 此外, 将
EventSetter
处理程序的方法名称从常规应用程序和页面标记中抽象化。
另一个将 WPF 的路由事件和动画功能结合在一起的专用语法是
EventTrigger
。 与 一样,
EventSetter
只能为路由事件声明
EventTrigger
。 通常,
EventTrigger
声明为样式的一部分,但
EventTrigger
可以在页面级元素上声明为 集合的
Triggers
一
ControlTemplate
部分,或在 中声明 。 使用
EventTrigger
,可以指定当路由事件到达其路由中的某个元素(这个元素针对该事件声明了
EventTrigger
)时将运行的
Storyboard
。 与只是处理事件并且使其启动现有情节提要相比,
EventTrigger
的优势在于,
EventTrigger
可对情节提要及其运行时行为提供更好的控制。 有关详细信息,请参阅
启动情节提要后使用事件触发器控制情节提要
。
有关路由事件的详细信息
在你自己的类中创建自定义路由事件时,可以使用本文中的概念和指南作为起点。 还可以使用专用事件数据类和委托来支持自定义事件。 路由事件所有者可以是任何类,但路由事件必须由或
ContentElement
派生类引发和处理
UIElement
才能发挥作用。 有关自定义事件的详细信息,请参阅
创建自定义路由事件
。
EventManager
RoutedEvent
RoutedEventArgs
将路由事件标记为“已处理”和“类处理”
自定义依赖属性
WPF 中的树
弱事件模式