以前在Windform开发中,大家都熟悉事件,外部事件,如键盘输入、鼠标移动、按动鼠标都由OS系统转换成相应的消息发送到应用程序的消息队列。每个应用程序都有一段相应的程序代码来检索、分发这些消息到对应的窗体,然后由窗体的处理函数来处理。 内部事件通过委托的方式处理。而WPF通过事件路由(event routing)的概念,增强了.net事件模型。事件路由允许源自某个元素的事件由另外一个元素来处理。
事件路由为在最合适的地方编写紧凑、组织良好的用于处理事件的代码,提供了灵活性。要使用WPF内容模型,事件路由也是必须的。内容模型允许使用许多不同的元素构建简单元素。下面看看我如何定义一个路由事件。
1、定义路由事件
WPF定义路由事件的方式和定义依赖属性特别相似,路由事件也是由静态成员和在静态构造函数中注册,并对window的事件进行了封装,由于所有事件必须基于界面,所以能够添加事件的基础类为System.Windows.UIElement,所以我们定义如下:
class Example : UIElement { //定义事件 public static readonly RoutedEvent testEvent; static Example() { Example.testEvent = EventManager.RegisterRoutedEvent("Test", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Example)); } public event RoutedEventHandler Test { add { this.AddHandler(Example.testEvent, value); } remove { this.RemoveHandler(Example.testEvent, value); } } /// <summary> /// 触发事件 /// </summary> public void TestHandler() { RoutedEventArgs e = new RoutedEventArgs(Example.testEvent,this); this.RaiseEvent(e); } }
事件的使用:
public partial class MainWindow : Window { Example example = new Example(); public MainWindow() { InitializeComponent(); example.Test += E_Test; } private void E_Test(object sender, RoutedEventArgs e) { MessageBox.Show("事件被调用"); } private void Button_Click(object sender, RoutedEventArgs e) { example.TestHandler(); } }
我们点击界面上的案例,则会触发弹出事件被调用,我们分析一下整个过程:
步骤1:申明事件
public static readonly RoutedEvent testEvent;
步骤2:注册事件
我们使用EventManager类的RegisterRoutedEvent函数进行注册路由事件,如下:
public static RoutedEvent RegisterRoutedEvent( string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType )
name:路由事件的名称,该名称在所有者类型中必须是唯一的,并且不能为空或者null.
RoutingStrategy:枚举当前事件的策略,三个选项
- Bubble:路由事件使用冒泡策略,以便事件实例通过树向上路由(从事件元素到根)。
- Direct:路由事件不通过元素树路由,但支持其他路由的事件功能,例如类处理 EventTrigger 或 EventSetter。
- Tunnel:路由事件使用隧道策略,以便事件实例通过树向下路由(从根到源元素)。
handlerType:事件处理程序的类型
ownerType:事件的拥有者类型
路由事件通过RaiseEvent函数触发,RaiseEvent函数的申明如下:
RoutedEventArgs e = new RoutedEventArgs(Example.testEvent,this); this.RaiseEvent(e);