首页 > 代码库 > WPF编程宝典之路由事件(一)

WPF编程宝典之路由事件(一)

路由事件是更具有传播能力的事件——它们可在元素树中向上冒泡和向下隧道传播,并且沿着传播路径被事件处理程序处理。

可通过传统的方式使用路由事件——通过关联具有正确签名的事件处理程序。

 

1.定义、注册和封装路由事件

与依赖项属性一样,路由事件由只读的静态字段表示,在静态构造函数中注册,并通过标准的.net事件定义进行封装。

 1 public abstract class ButtonBase : ContentControl
 2 {
 3     //定义事件
 4     public static readonly RoutedEvent ClickEvent;
 5     //注册事件
 6     static ButtonBase()
 7     {
 8         ButtonBase.ClickEvent = EventManager.RegisterRutedEvent(
 9         "Click",RoutingStrategy.Bubble,
10         typeof(RoutedEventHandler),typeof(ButtonBase));
11     }
12 }

路由事件使用EventManager.RegisterRoutedEvent()方法注册。

注册时需要指明:

  • 事件的名称
  • 路由类型
  • 定义事件处理程序语法的委托
  • 拥有事件的类。

通常,路由事件通过普通的.NET事件进行封装,从而使所有.net语言都能访问。事件封装器可使用AddHandler()和RemoveHandler()方法添加和删除已注册的调用程序,这两个方法在FrameworkElement基类中定义,并被每个WPF元素继承。

 

2.共享路由事件

1    UIElement.MouseUpEvent = Mouse.MouseUpEvent.AddOwner(typeof(UIElement));
UIElement(该类是所有普通WPF元素的起点)类通过Routed-Event.AddOwner()方法重用MouseUp事件。


3.引发路由事件

事件不通过传统的.NET事件封装器引发,而是使用RaiseEvent()方法引发,所有元素都从UIElement类继承了该方法
1 RoutedEventArgs e = new RoutedEventArgs(ButtonBase.ClickEvent, this);
2 base.RaiseEvent(e);

RaiseEvent()方法负责为每个已经通过AddHandler()方法注册的调用程序引发事件。

所有WPF事件都为事件签名使用熟悉的.NET约定,每个事件处理程序的第一个参数(sender参数)都提供引发该事件的对象的引用;第二个参数EventArgs对象,该对象与其他重要的附加细节绑定在一起。例如,MouseUp事件提供了一个MouseEventArgs对象,用于指示当事件发生时按下了哪些鼠标:

1 private void img_MouseUp(object sender, MouseButtonEventArgs e)
2 {
3 
4 }

 

4.处理路由事件

最常用的方法是XAML标记添加事件特性:

1    <Image Source="happyface.jpg" Stretch="None"
2     Name="img" MouseUp="img_MouseUp" />

也可以通过代码连接事件:

1    img.MouseUp += new MouseButtonEventHandler(img_MouseUp);
2 //或者
3 //img.MouseUp += img_MouseUp;

 

5.路由事件出现的三种方式
  • 与普通.net事件类似的直接路由事件。事件源于一个元素,不传递给其他元素,例如MouseEnter事件;
  • 在包含层次中向上传递的冒泡路由事件(bubbling event)。例如MouseDown事件,首先由被单击的元素引发,接下来被元素的父元素引发,然后被父元素的父元素引发,直到元素树的顶部;
  • 在包含层次中向下传递的隧道路由事件(tunneling event)。例如PreviewKeyDown事件,首先在窗口级别上,然后是更具体的容器,直至到达当按下键时具有焦点的元素。

6.RoutedEventArgs类
名称 说明
Source 指示引发了事件的对象
OriginalSource 指示最初是什么对象引发了事件
RoutedEvent 通过事件处理程序为触发的事件提供RoutedEvent对象
Handled 该属性允许终止事件的冒泡或隧道过程。如果控件将Handled属性设为true,那么事件就不会继续传递,也不会再为其他任何元素引发该事件。


7.附加事件
如果上一层的控件不支持下一层控件的事件,而需要将下一层的若干控件添加相同的事件处理方法,需要用到“附加事件”
1 <StackPanel Button.Click="DoSomething" Margin="5">
2     <Button Name="cmd1">Command 1</Button>
3     <Button Name="cmd2">Command 1</Button>
4     <Button Name="cmd3">Command 1</Button>
5 <StackPanel>

这样所有的Button的单击事件都可以被捕获。



8.生命周期事件
(1)所有元素的生命周期事件
名称 说明
Initialized 当元素被实例化,并以已根据XAML标记设置了元素的属性之后发生
Loaded 当整个窗口已经初始化并应用了样式和数据绑定,该事件发生。
Unloaded 当元素被释放时,该事件发生。
(2)Window类的生命周期事件
  • SourceInitialized
  • ContentRendered
  • Activated
  • Deactivated
  • Closing
  • Closed
(3)键盘事件
  • PreviewKeyDown
  • KeyDown
  • PreviewTextInput
  • TextInput
  • PreviewKeyUp
  • KeyUp
(4)获取键盘状态
  • IsKeyDown
  • IsKeyUp
  • IsKeyToggled
  • GetKeyStates
(5)鼠标单击
  • PreviewMouseLeftButtonDown
  • MouseLeftButtonDown
  • PreviewMouseLeftButtonUp
  • MouseLeftButtonUp



 

WPF编程宝典之路由事件(一)