RoutedEvent
一、直接事件(CLR事件)
事件的前身是消息(Message),Windows是消息驱动的操作系统(消息触发算法逻辑),运行在其上的程序也照此机制运行。微软将消息机制封装成了更易理解的时间模型:
繁琐的消息驱动机制在事件模型中被简化为三个要素:
- 事件拥有者: 消息的发送者,事件(event)被触发则消息被发送;
- 事件响应者: 消息的接收、处理者,事件处理器(EventHandler)对事件做出响应;
- 事件订阅关系: 使event和EventHandler关联起来;
- 事件:使用enent关键字修饰的委托类成员变量;
- 事件处理器:函数。
这种模型中,事件的响应者通过订阅关系直接关联在事件拥有者的事件上,这种模型称为直接事件模型或CLR事件模型。
以WPF中的Button为例:
/*
* 以这里的按钮为例说明CLR事件模型的对应关系:
* 事件拥有者:toPage1(按钮);
* 事件:toPage1.Click;
* 事件响应者:ContentControl(页面);
* 事件处理器:ToPage1_Click方法(事件响应者通过事件处理器对事件作出响应);
* 订阅关系:在MainWindow.g.cs文件中用如下语句确立订阅关系
* this.toPage1.Click += new System.Windows.RoutedEventHandler(this.ToPage1_Click);
*/
private void ToPage1_Click(object sender, RoutedEventArgs e)
{
if (page1 == null)
{
page1 = new Page1();
}
PageView.Content = new Frame()
{
Content = page1
};
}
直接事件有两个弊端:
- 每对消息是“发送→响应”关系,必须建立显式的点对点订阅关系;
- 事件的宿主必须能够直接访问事件的响应者,不然无法建立订阅关系。
二、路由事件
路由事件与直接事件的区别:
- 直接事件激发时,发送者直接将消息通过事件订阅交送给事件响应者,响应者使用其事件处理器方法对事件的发生作出响应、驱动程序逻辑按客户需求运行;
- 路由事件的时间拥有者和事件响应者之间没有直接显式的订阅关系,事件拥有者只负责激发事件,并不关心由谁响应,而事件的响应者装有事件侦听器,针对某类事件进行侦听。
路由事件沿逻辑树向上传递,按顺序响应!
编写书中例程验证路由事件的传递路径:
C#:
public partial class Built_in_RoutedEvent : Page
{
public Built_in_RoutedEvent()
{
InitializeComponent();
/*
* 为gridRoot安装针对Button.Click事件的侦听器:
* 安装侦听器有两种方法:
* 一、在xaml中直接添加:如当前代码实现;
* 在xaml中直接写方法:Button.Click/ButtonBase.Click = “方法名”;
* 二、自定义:
* 在窗体的构造器中调用gridRoot的AddHandler方法,把想监听的事件与事件处理器关联起来,自定义语句如下:
* //this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.GridRoot_Click));
* //this.gridA.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.GridA_Click));
*/
}
//使用WPF内置路由事件
#region
//在xaml中用Button直接生成(没有自动提示)
private void GridA_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("response by gridA");
}
//在xaml中用ButtonBase直接生成(有自动提示)
private void GridRoot_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
}
//自定义事件处理器
//private void ButtonClicked(object sender, RoutedEventArgs e)
//{
// MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
//}
#endregion
}
xaml:
<Grid x:Name="gridRoot" Background="Lime" Grid.Column="0" Grid.Row="0"
ButtonBase.Click="GridRoot_Click">
<Grid x:Name="gridA" Margin="10" Background="Blue" Button.Click="GridA_Click">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Canvas x:Name="canvasLeft" Grid.Column="0" Background="Red" Margin="10">
<Button x:Name="buttonLeft" Content="Left" Width