路由事件是更强传播能力的事件,在元素树中向上冒泡和向下隧道传播,沿着传播路径被事件处理程序处理。
与依赖项属性一样,同样可以通过传统事件的使用方式使用路由事件。
一、写法结构
public class 控件:ContentControl
{
/// <summary>
/// 路由事件定义
/// </summary>
public static readonly RoutedEvent 操作Event;
/// <summary>
/// 共享路由事件
/// </summary>
public static readonly RoutedEvent MouseUpEvent;
//构造函数
static 控件()
{
//路由事件注册
控件.操作Event = EventManager.RegisterRoutedEvent("操作",RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(控件));
//共享路由事件 例如重用MouseUpEvent
控件.MouseUpEvent = ContentControl.MouseUpEvent.AddOwner(typeof(UIElement));
}
/// <summary>
/// 传统事件包装
/// </summary>
public event RoutedEventHandler 操作
{
add
{
base.AddHandler(控件.操作Event,value);
}
remove
{
base.RemoveHandler(控件.操作Event, value);
}
}
}
二、引发与处理
引发路由事件
RaiseEvent()方法
处理事件路由
关联事件处理程序
<Button x:Name="test_btn" MouseUp="test_btn_MouseUp">444</Button>
或
test_btn.MouseUp += test_btn_MouseUp;
或
test_btn.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(test_btn_MouseUp));
或
test_btn.AddHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(test_btn_MouseUp));
/// <summary>
/// 事件处理程序
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void test_btn_MouseUp(object sender, MouseButtonEventArgs e)
{
//处理逻辑
}
断开事件处理程序
test_btn.MouseUp -= test_btn_MouseUp;
或
test_btn.RemoveHandler(Button.MouseUpEvent,new MouseButtonEventHandler(test_btn_MouseUp));
三、路由事件出现的三种方式
1.直接路由事件(direct event):源于一个元素且不传递。如;MouseEnter
2.冒泡路由事件(bubbling event):由子及父,直至顶部。如MouseDown
3.隧道路由事件(tunneling event):由父及子,从窗口级别直至具有焦点的元素。如PreviewKeyDown
隧道路由事件通常都以Preview开头,而且WPF通常将其和冒泡路由事件成对定义,且隧道总是先于冒泡被触发。
如果隧道路由事件标记Handled=True,那就不会触发冒泡路由事件,原因是两个事件共享一个RoutedEventArgs类实例,所以隧道路由事件标记Handled=True需谨慎。
查找文档或源代码,可以在源代码的构造函数中看到事件注册时定义的路由类型枚举值。
Click = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));
四、RoutedEventArgs类
所有WPF事件参数类都是继承于此。
存在属性Source、OriginalSource、RoutedEvent、Handled。
Source:指示引发了事件的对象。
OriginalSource:可以用来确定事件最初发生的位置。
RoutedEvent:可以用来使同一个事件处理程序处理不同的事件,根据触发传递进来的不同RoutedEvent,执行不同的逻辑代码。
Handled:终止事件的传递,Handled属性值为true时,停止传递。
五、Click事件
专用于基于按钮的控件,不会引发MouseUp事件的传递,Handled标志被设置为True,是比MouseUp更高一级的事件。
六、处理被挂起的事件
AddHandler()有一个具有第三个参数(类型bool)的重载版本,可使元素接收到已将Handled=True的事件。
test_btn.AddHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(test_btn_MouseUp),true);
七、附加事件
可在父级容器上关联子级元素的公共事件
<StackPanel x:Name="test_sp" ButtonBase.Click="StackPanel_Click">
<Button>444</Button>
<Button>555</Button>
<Button>666</Button>
</StackPanel>
或
test_sp.AddHandler(ButtonBase.ClickEvent,new RoutedEventHandler(StackPanel_Click));
在StackPanel_Click事件处理程序中,即可根据sender参数判断是哪个按钮触发的事件,在此过程中可为button设置name或tag等区分标识。
这里使用的是按钮基类ButtonBase的Click事件,对于不同业务场景,可以使用特定元素类型的事件,如:Button.Click、RadioButton.Checked等