WPF入门(二):初遇RoutedEvent

先做个简单的东西吧,新建个wpf项目,拖动一个menu控件到窗体里。使用设计器添加几个菜单子项,并双击菜单注册事件,代码如下:
代码
 1 <Window x:Class="WpfApplication1.WinMain"
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4     Title="WinMain" Height="494" Width="715">
 5     <Grid>
 6         <Grid.ColumnDefinitions>
 7             <ColumnDefinition Width="371*" />
 8             <ColumnDefinition Width="344*" />
 9         </Grid.ColumnDefinitions>
10         <Menu Height="25" Name="menu1" VerticalAlignment="Top" Grid.ColumnSpan="2">
11             <MenuItem Header="第一级菜单" Click="MenuItem_Click">
12                 <MenuItem Header="第二级菜单1" />
13                 <MenuItem Header="第二级菜单2" />
14             </MenuItem>
15         </Menu>
16     </Grid>
17 </Window>
18   
19 
20   /// <summary>
21     /// WinMain.xaml 的交互逻辑
22     /// </summary>
23     public partial class WinMain : Window
24     {
25         public WinMain()
26         {
27             InitializeComponent();
28         }
29 
30         private void MenuItem_Click(object sender, RoutedEventArgs e)
31         {
32             object obj = e.Source;
33             bool handled = e.Handled;
34 
35             RoutedEvent routedEvent = e.RoutedEvent;
36             RoutingStrategy routingStrategy = routedEvent.RoutingStrategy;
37 
38 
39             MessageBox.Show("触发了事件 \r\n 源:" + e.Source.ToString());
40         }
41 
42     }

我们重点看节点Menu和MenuItem,menu是菜单的根节点。header属性是菜单的标题。(顺便说一句,在winform里这些都是设置属性"Text"的,而在wpf里,大多变成"Content"属性)。而让人惊讶的是 “在代码设计器中,我们只能对一级菜单注册事件”,查看代码第11行里。有句“Click="MenuItem_Click"” 熟悉 html人都能明白这个意思,就是注册一个事件,事件名字是“MenuItem_Click”,而事件的实现代码当然是在"CodeBehind"代码后置文件里找了。这里 “二级菜单1”和“二级菜单2”两个菜单的单击都会触发"MenuItem_Click"。也就是说“子控件里的单击 触发了 父控件里注册的事件”。其实是个 “事件路由(RoutedEvent)”,流程如下:

1.先触发子控件的click事件,(本示例没有订阅该事件,等下我们做个订阅尝试)。

2.再触发父控件的click事件。

3.依次再触发该控件的上一级父控件的事件。

这里就有了事件 触发策略问题。即事件如何传递。

 我们看下 注册事件的代码 private void MenuItem_Click(object sender, RoutedEventArgs e) ,方法签名里和我们常见的方法签名区别是这个这个参数RoutedEventArgs ,该参数属性有(摘自msdn):

  名称 说明
Handled 获取或设置一个值,该值指示路由事件在路由过程中的事件处理当前状态。
OriginalSource 在父类进行任何可能的 Source 调整之前,获取原始报告源(由纯粹命中测试确定)。
RoutedEvent 获取或设置与此 RoutedEventArgs 实例关联的 RoutedEvent
Source 获取或设置对引发事件的对象的引用。

我们在事件中,如果想终止该事件的继续传递,设置e.Handled= true就可以了。

事件使用的委托的方法签名如下:

public delegate void RoutedEventHandler(
	Object sender,
	RoutedEventArgs e
)
实际上一切都是由RoutedEvent 对象来管理的。也就是说。RoutedEvent处理了事件的传递方式。

名称 说明
HandlerType 获取路由事件的处理程序类型。
Name 获取路由事件的标识名称。
OwnerType 获取路由事件的已注册所有者类型。
RoutingStrategy 获取路由事件的路由策略。

public enum RoutingStrategy 路由策略的枚举类型如下:

成员名称 说明
Tunnel 路由事件使用隧道策略,以便事件实例通过树向下路由(从根到源元素)。
Bubble 路由事件使用冒泡策略,以便事件实例通过树向上路由(从事件元素到根)。
Direct 路由事件不通过元素树路由,但支持其他路由事件功能,例如类处理、EventTriggerEventSetter

我们可以设置我们RoutedEvent的传递方式,当然这要自己写控件的时候才用得到。

 

稍候待续...

原文地址:https://www.cnblogs.com/vir56k/p/1934578.html