本文内容
- 先决条件
- 路由事件步骤
- 示例
Windows Presentation Foundation (WPF) 应用程序开发人员和组件作者可以创建自定义路由事件,用于扩展公共语言运行时 (CLR) 事件的功能。 本文介绍创建自定义路由事件的基本知识。
1、先决条件
本文假定你对路由事件有基本的了解,并且已阅读
路由事件概述。 若要遵循本文中的示例,如果熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 Windows Presentation Foundation (WPF) 应用程序,将会很有帮助。
2、路由事件步骤
创建路由事件的基本步骤如下:
使用RegisterRoutedEvent方法注册RoutedEvent。
注册调用返回一个
RoutedEvent
实例,称为路由事件标识符,该标识符包含已注册的事件名、路由策略
和其他事件详细信息。 将该标识符分配给静态只读字段。 按照惯例:- 具有浮升
策略的路由事件的标识符命名为Event
。 例如,如果事件名为Tap
,则标识符应命名为TapEvent
。 - 具有
隧道策略的路由事件的标识符命名为PreviewEvent
。 例如,如果事件名为Tap
,则标识符应命名为PreviewTapEvent
。
- 具有浮升
定义 CLRadd和remove事件访问器。 如果没有 CLR 事件访问器,你就只能通过直接调用UIElement.AddHandler和UIElement.RemoveHandler方法来添加或删除事件处理程序。 使用 CLR 事件访问器时,你会获得以下事件处理程序分配机制:
- 对于 Extensible Application Markup Language (XAML),可以使用属性语法来添加事件处理程序。
- 对于 C#,可以使用
+=
和-=
运算符来添加或删除事件处理程序。 - 对于 VB,可以使用AddHandler和RemoveHandler语句来添加或删除事件处理程序。
添加用于触发路由事件的自定义逻辑。 例如,你的逻辑可能会基于用户输入和应用程序状态触发事件。
3、示例
以下示例在自定义控件库中实现CustomButton
类。 派生自Button的CustomButton
类:
- 使用RegisterRoutedEvent方法注册一个名为
ConditionalClick
的RoutedEvent,并在注册期间指定浮升
策略。 - 将从注册调用返回的
RoutedEvent
实例分配给名为ConditionalClickEvent
的静态只读字段。 - 定义 CLRadd和remove事件访问器。
- 添加自定义逻辑,以在单击
CustomButton
并应用外部条件时引发自定义路由事件。 虽然示例代码从重写的OnClick
虚拟方法内引发ConditionalClick
路由事件,但你可选用任何方式来引发事件。
public class CustomButton : Button{// Register a custom routed event using the Bubble routing strategy.public static readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent(name: "ConditionalClick",routingStrategy: RoutingStrategy.Bubble,handlerType: typeof(RoutedEventHandler),ownerType: typeof(CustomButton));// Provide CLR accessors for assigning an event handler.public event RoutedEventHandler ConditionalClick{add { AddHandler(ConditionalClickEvent, value); }remove { RemoveHandler(ConditionalClickEvent, value); }}void RaiseCustomRoutedEvent(){// Create a RoutedEventArgs instance.RoutedEventArgs routedEventArgs = new(routedEvent: ConditionalClickEvent);// Raise the event, which will bubble up through the element tree.RaiseEvent(routedEventArgs);}// For demo purposes, we use the Click event as a trigger.protected override void OnClick(){// Some condition combined with the Click event will trigger the ConditionalClick event.if (DateTime.Now > new DateTime())RaiseCustomRoutedEvent();// Call the base class OnClick() method so Click event subscribers are notified.base.OnClick();}}
该示例包含一个单独的 WPF 应用程序,该应用程序使用 XAML 标记将CustomButton
实例添加到StackPanel,并将Handler_ConditionalClick
方法分配为CustomButton
和StackPanel1
元素的ConditionalClick
事件处理程序。
WPF 应用程序在代码隐藏中定义Handler_ConditionalClick
事件处理程序方法。 事件处理程序方法只能在代码隐藏中实现。
// The ConditionalClick event handler.private void Handler_ConditionalClick(object sender, RoutedEventArgs e){string senderName = ((FrameworkElement)sender).Name;string sourceName = ((FrameworkElement)e.Source).Name;Debug.WriteLine($"Routed event handler attached to {senderName}, " +$"triggered by the ConditionalClick routed event raised on {sourceName}.");}// Debug output when CustomButton is clicked:// Routed event handler attached to CustomButton,// triggered by the ConditionalClick routed event raised on CustomButton.// Routed event handler attached to StackPanel1,// triggered by the ConditionalClick routed event raised on CustomButton.
单击CustomButton
时:
ConditionalClick
路由事件在CustomButton
上引发。- 触发了附加到
CustomButton
的Handler_ConditionalClick
事件处理程序。 ConditionalClick
路由事件在元素树中向上遍历到StackPanel1
。- 触发了附加到
StackPanel1
的Handler_ConditionalClick
事件处理程序。 ConditionalClick
路由事件继续向上遍历元素树,可能会触发附加到其他已遍历元素的其他ConditionalClick
事件处理程序。
Handler_ConditionalClick
事件处理程序获取有关触发它的事件的以下信息:
- sender对象,它是事件处理程序附加到的元素。 处理程序首次运行时,
sender
为CustomButton
,第二次运行时则为StackPanel1
。 - RoutedEventArgs.Source对象,它是最初引发事件的元素。 在本示例中,
Source
始终为CustomButton
。
备注
路由事件和 CLR 事件之间的一个主要区别是,路由事件遍历元素树来查找处理程序,而 CLR 事件不遍历元素树,处理程序只能附加到引发事件的源对象。 因此,路由事件sender
可以是元素树中的任何已遍历的元素。
你可以像创建浮升事件一样创建隧道事件,但将在Tunnel事件注册调用中设置路由策略。