WPF-事件
什么是事件
事件的前生为消息,微软将消息的机制封装成为了事件模型,也就是说事件为消息机制。
事件模型隐藏了消息机制的很多细节,烦琐的消息驱动机制在事件模型中被简化为3个关键点
这里以winfrom 中 button中click事件为例,
事件的拥有者 | button这个控件 | 消息的发送者 |
---|---|---|
事件的响应者 | 窗体本身 | 消息的接收者,消息接收者使用其事件处理器event handler 对事件做出相应 |
订阅关系 | this.button1.Click += new System.EventHandler(this.button1_Click); | winfrom订阅button事件 本质上就是让b.event 与w.eventHandler关联起来 |
在CLR直接事件模型中,事件的相应者与事件的拥有者之间必须建立事件订阅这个专线联系,这样至少有两个弊端
必须建立显示的点对点的订阅关系
事件的拥有着必须能之访问事件的相应者,否则无法建立订阅关系
路由事件
为了降低事件订阅带来的耦合度和代码量,WPF推出了路由事件机制。与CLR事件不同之处在于事件的拥有着和响应者之间没有直接显示的订阅关系,事件的拥有者只负责激发事件,事件的相应者安装事件监听器,针对某类事件进行侦听和处理。
尽管WPF推出了路由事件,但任支持传统的直接事件模型。
如何简单使用路由事件呢,直接在窗体构造器中调用addHandler方法将想监听的事件与事件处器关联起来
// 按钮点击事件
this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.justDoIt));
private void justDoIt(object sender ,RoutedEventArgs e)
{
MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
}
路由事件
自定义路由事件分为3个步骤,这与自定义依赖属性很相似
class TimeButton : Button
{
// 申明和注册路由事件
public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));
// CLR包装
public event RoutedEventHandler ReportTime
{
add { this.AddHandler(ReportTimeEvent, value); }
remove { this.RemoveHandler(ReportTimeEvent, value); }
}
// 激发路由事件的方法
protected override void OnClick()
{
base.OnClick();
ReportTimeEventArgs args = new ReportTimeEventArgs(ReportTimeEvent, this);
args.ClickTime = DateTime.Now;
this.RaiseEvent(args);
}
}
public class ReportTimeEventArgs : RoutedEventArgs
{
public ReportTimeEventArgs(RoutedEvent routedEvent,object source):base(routedEvent ,source)
{
}
public DateTime ClickTime { get; set; }
}
注册路由事件需要了解EventManager.RegisterRoutedEvent的四个方法参数
第一个为路由事件名称,string类型,名称与包装事件名称一致
第二个为路由事件策略,一共三种策略,bubble,tunnel,dircct
第三个为指定事件处理器的类型
第四个为事件的宿主类型
附加事件
特殊的路由事件,但事件的宿主不具备在用户界面的上显示的能力,也就是否继承UIElemeent类是区分其关键,附加事件通常有这几类
- Binding
- Mouse
- Keyboard
随笔资料大量来自于《深入浅出WPF》 和官方文档