事件学习二--自定义路由事件
WPF中有2种树,一种叫做逻辑树(LogicalTree),另一种叫可视元素树(VisualTree),逻辑树是可视元素树的一棵子树,路由事件沿着VisualTree传递。
路由事件的事件拥有者和事件响应者之间没有直接显示的订阅关系,事件的拥有者只负责激发事件,事件由谁响应并不知道,事件的响应者则安装事件监听器,针对某类事件进行侦听,尽管WPF推出路由事件机制,但它仍然支持传统的直接事件模型。
WPF内置的路由事件
<Grid Name="gridRoot"> <Grid x:Name="gridA"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition/> </Grid.ColumnDefinitions> <Canvas Name="canvasLeft" > <Button x:Name="leftbtn" Content="left" Width="120" Height="25"/> </Canvas> <Canvas Name="canvasRight" Grid.Column="1" > <Button x:Name="rightbtn" Content="right" Width="120" Height="25"/> </Canvas> </Grid> </Grid>
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.ButtonClicked)); } private void ButtonClicked(object sender,RoutedEventArgs e) { MessageBox.Show((e.OriginalSource as FrameworkElement).Name); } }
由于所有的WPF事件参数类继承自RoutedEventArgs,因此任何事件处理程序都可以使用以下属性。
- Source:表示LogicalTree上的消息源头。
- OriginalSource:表示VisualTree上的源头
- Handled:该属性允许终止事件的冒泡或隧道过程。
- RouteEvent:通过事件处理程序为触发的事件提供RoutedEvent对象。如果同一个事件处理程序处理不同的事件,这一信息是非常有用的。
自定义路由事件
三个步骤:
(1) 声明并注册路由事件。
(2)为路由事件添加CLR事件包装
(3)创建可以激发路由事件的方法
public abstract class ButtonBase:ContentControl {
//声明并注册路由事件 public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase)); //为路由事件添加CLR事件包装 public event RoutedEventHandler Click { add { this.AddHandler(ClickEvent, value); } remove { this.RemoveHandler(ClickEvent, value); } }
//激发路由事件的方法,此方法用户在单击鼠标时会被Windows系统调用 protected virtual void OnClick() { RoutedEventArgs newEvent = new RoutedEventArgs(ButtonBase.ClickEvent, this); this.RaiseEvent(newEvent); } }
EventManager.RegisterRoutedEvent的四个参数
1)第一个参数string类型,被称为路由事件的名称,与CLR属性包装器的名称一致。
2)第二个参数为路由事件的策略,路由事件一般使用以下三种路由策略:
- Bubble冒泡:由事件源向上传递一直到最外层容器(Window或者Page)。
- Direct直达式:模仿CLR直接事件,直接将事件消息送达到事件处理器。
- Tunnel隧道:从元素树的根部调用事件处理程序并依次向下深入直到事件源。
一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件。
3)第三个参数用于指定事件处理器的类型。事件处理器的返回值类型和参数列表必须与此参数指定的委托一致。
4)第四个参数用于指定路由事件的宿主是哪个类型。
浙公网安备 33010602011771号