WPF自学入门(三)WPF路由事件之内置路由事件
2021-02-10 00:17
有没有想过在.NET中已经有了事件机制,为什么在WPF中不直接使用.NET事件要加入路由事件来取代事件呢?最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,是否还记得在WPF自学入门(一)XAM基本知识中提到过两棵树,逻辑树LogicalTree 和可视化树 VisualTree,那么它们分别是什么?
举个例子:
上面的代码就是逻辑树LogicalTree,一个Grid里面镶嵌了其他控件或布局组件,相当于一棵树中的叶子。而可视化树VisualTree是什么?它就是一个树中的树叶里面的结构,用放大镜看一下,其实叶子里面的结构也是一颗树结构
举个例子:
既然WPF中使用这样的一个设计理念,路由事件就是特别为WPF而生,它的功能就是可以把一个事件从触发点沿着树向上或者向下传播,需要对这个事件作出反应的地方就添加一个监听器,就会有相应的反应,当然,它的传递是可以用代码来停止。 好了,我已经大概了解了一些路由事件。下面先来了解一下WPF内置的路由事件和原理,然后我们来创建一个属于自己的路由事件。
1、WPF内置的路由事件
新建WPF项目,在页面上放置按钮。然后在Window,Grid,Button标签上使用MouseDown事件,如下图
添加后置代码
调试运行,鼠标右键点击按钮,会依次弹出下列三个对话框。
ButtonMouseDown事件被触发:
GridMouseDown事件被触发:
WindowMouseDown事件被触发:
我点击的是按钮,为什么Grid和Window也会引发事件呢?其实这就是路由事件的机制,引发的事件由源元素逐级传到上层的元素,Button—>Grid—>Window,这样就导致这几个元素都接收到了事件。(注意一定是鼠标右键,否则引发不了事件。)
如果想Grid和Window不处理这个事件,只需要在Button_MouseDown这个方法中加上e.Handled = true; 这样就表示事件已经被处理,其他元素不需要再处理这个事件了。
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Button被点击!");
e.Handled = true;
}
如果想要Grid参与事件处理只需要给它AddHandler即可
grid.AddHandler(Grid.MouseDownEvent, new RoutedEventHandler(Grid_MouseDown), true);
到这里我想大家应该对路由事件有了大概认识了。路由事件实际上分两类:气泡事件和预览事件(也叫做隧道事件)。上文中的例子就是气泡事件。
2、内置路由事件学习总结:
气泡事件是WPF路由事件中最为常见,它表示事件从源元素扩散传播到可视树,直到它被处理或到达根元素。这样我们就可以针对源元素的上方层级对象处理事件。(例如MouseDown)
预览事件采用另一种方式,从根元素开始,向下遍历元素树,直到被处理或到达事件的源元素。这样上游元素就可以在事件到达源元素之前先行截取并进行处理。根据命名惯例,预览事件带有前缀 Preview(例如 PreviewMouseDown)。
气泡事件和预览事件区别
气泡事件:在Button上点击,首先弹出“Button”,再弹出“Grid”,最后弹出“Window”。
预览事件:在Button上点击,首先弹出“Window”,再弹出“Grid”,最后弹出“Button”。
看到了这个顺序区别,那么我们加入e.Handled=true的时机也要不同
PS:本人也是WPF的初学者,如有不对的地方,欢迎在评论区多多指教,学习,为了分享,为了提高。