Silverlight实用窍门系列:35.细解Silverlight冒泡路由事件和注册冒泡路由事件【附带实例源码】

简介:

Silverlight中的事件分为普通事件和冒泡路由事件,它并没有包括WPF中的隧道路由事件,在本章中将详细讲解冒泡路由事件和如何注册一个冒泡路由事件。

一、细解冒泡路由事件

冒泡路由事件可以比喻为:一个父对象X包含子对象A,在子对象A中没有事件处理程序,但是父对象X中有一个鼠标左击事件处理程序。当用户点击子孙对象A时,这个事件又鼠标左击冒泡传递到父对象X。父对象的事件处理程序就处理这次点击事件。

总结出来就是:冒泡路由事件是从子孙的元素传递到父对象事件处理程序中进行处理的一种解决方案,直到这个事件传递到最上层根对象。

如果子对象有这类路由事件(如:MouseLeftButtonDown)的处理程序,父对象也有这类路由事件(如:MouseLeftButtonDown)的处理程序的时候,会出现什么情况呢?答案是既执行子对象的MouseLeftButtonDown处理程序,又执行父对象的MouseLeftButtonDown处理程序。如果我们想在某个子对象触发MouseLeftButtonDown路由事件的时候,只让该子对象执行MouseLeftButtonDown处理程序而父对象不执行它的MouseLeftButtonDown处理程序,我们应该如何办呢?答案是设置事件的e.Handled=ture。中止事件的冒泡路由,表示这个事件已经处理完毕,不用继续冒泡往上传递。

现在我们通过一个实例程序来看冒泡路由事件的处理,首先我们来看XAML代码:

<Grid Width="200" Height="200" x:Name="GridA" HorizontalAlignment="Left" Background="AliceBlue"
 MouseLeftButtonDown="LayoutRoot_MouseLeftButtonDown">
 <Ellipse Height="44" HorizontalAlignment="Left" Fill="DarkKhaki" Name="ellipseFirst"
 Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="86" />
 <Ellipse Height="44" HorizontalAlignment="Left" Fill="BlanchedAlmond" Margin="0,71,0,0"
 Name="ellipseSecond" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top"
 Width="94" MouseLeftButtonDown="ellipse2_MouseLeftButtonDown" />
</Grid>

我们为一个名为GridA的Grid对象下添加两个子对象圆,这两个圆的Name分别是ellipseFirst和ellipseSecond,ellipseFirst没有任何的事件处理程序,而ellipseSecond有一个事件处理程序ellipse2_MouseLeftButtonDown,父对象有一个事件处理程序LayoutRoot_MouseLeftButtonDown。
#region 路由事件的原理
 private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
 //正在调用事件处理程序的对象
 FrameworkElement grid = sender as FrameworkElement;
 //获取到触发此次事件的对象
 FrameworkElement ellipse = e.OriginalSource as FrameworkElement;
 MessageBox.Show("引发事件的子对象名是:" + ellipse.Name + 
 "----子对象事件冒泡上来触发并且产生事件的父对象名是:" + grid.Name);
 }
 private void ellipse2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 { 
 //获取到触发此次事件的对象
 FrameworkElement ellipse = e.OriginalSource as FrameworkElement;
 //通过e.Handled设置为ture表示路由事件已处理拦截了事件,
 //不必冒泡到父对象的LayoutRoot_MouseLeftButtonDown去处理。
 MessageBox.Show("引发事件的对象名是:" + ellipse.Name + ",路由事件被拦截");
 e.Handled = true;
 }
 #endregion

在鼠标左键点击事件中的e.OriginalSource可以获取到触发事件的源对象。

在此实例中,我们点击圆ellipseFirst的时候,它没有任何事件处理程序,于是冒泡路由策略发生作用,此次点击事件由父对象的LayoutRoot_MouseLeftButtonDown事件处理程序进行处理。于是弹出以下界面:

当我们点击圆ellipseSecond的时候,它自身有一个事件处理程序,于是首先执行它自身的左键点击处理程序ellipse2_MouseLeftButtonDown,弹出以下界面:

二、注册冒泡路由事件

在Silverlight中我们使用UIElement.AddHandler 方法为对象注册冒泡路由事件处理程序。

public void AddHandler( RoutedEvent routedEvent,Delegate handler,bool handledEventsToo)
 //routedEvent 
 // 类型:System.Windows.RoutedEvent
 // 要处理的路由事件的标识符。

 //handler 
 // 类型:System.Delegate
 // 对处理程序实现的引用。

 //handledEventsToo 
 // 类型:System.Boolean
 // 如果为 true,则将按以下方式注册处理程序:即使路由事件在其事件数据中标记为已处理,
 // 也会调用该处理程序;如果为 false,则使用默认条件注册处理程序,
 // 即当路由事件已标记为已处理时,将不调用该处理程序。

下面我们来看一下实例的源码XAML文件代码如下:
<Grid Width="200" Height="200" x:Name="GridB" HorizontalAlignment="Right" Background="Aqua">
 <Ellipse Height="44" HorizontalAlignment="Left" Fill="Coral" Name="ellipseThird" 
 Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="86" />
 <Ellipse Height="44" HorizontalAlignment="Left" Fill="DarkSalmon" Margin="0,71,0,0"
 Name="ellipseFourth" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top"
 Width="94" MouseLeftButtonDown="ellipse2_MouseLeftButtonDown" />
</Grid>

在这里我们创建了一个名为GridB的Grid对象,在GridB对象内部我们创建两个圆分别是ellipseThird和ellipseFourth。其中ellipseFourth中我们添加了一个事件处理程序ellipse2_MouseLeftButtonDown。
#region 为GridB控件添加一个路由事件处理程序,并且设置一直都要处理这个路由事件
 private void UserControl_Loaded(object sender, RoutedEventArgs e)
 {
 //为GridB控件添加一个路由事件处理程序,并且设置一直都要执行此路由事件
 this.GridB.AddHandler(FrameworkElement.MouseLeftButtonDownEvent, 
 new MouseButtonEventHandler(GridB_MouseLeftButtonDown), 
 true);
 }

 private void GridB_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 {
 //处理这次事件的对象
 FrameworkElement grid = sender as FrameworkElement;
 //获取到触发事件的对象
 FrameworkElement ellipse = e.OriginalSource as FrameworkElement;
 MessageBox.Show("引发事件的子对象名是:" + ellipse.Name +
 "----子对象事件冒泡上来触发并且产生事件的父对象名是:" + grid.Name);
 }
 #endregion


在上一段代码中我们在控件的Loaded事件中为GridB注册了一个事件处理程序名为:GridB_MouseLeftButtonDown。注意我们在使用AddHandle注册这个程序的时候,设置了handledEventsToo为Ture,意味着我们不管子控件(ellipseThird和ellipseFourth)的自身事件处理程序中是否设置e.Handled是否为Ture,我们都要执行父控件的事件处理程序GridB_MouseLeftButtonDown。反之如果我们设置handledEventsToo为False,则根据子控件的e.Handled是否为Ture来决定是否冒泡路由到父控件处理。

下面我们来看看点击ellipseThird的时候弹出以下界面:

下面我们来看看点击ellipseFourth的时候,因为设置handledEventsToo为Ture,不管子控件(ellipseThird和ellipseFourth)的自身事件处理程序中是否设置e.Handled是否为Ture,我们都要执行父控件的事件处理程序GridB_MouseLeftButtonDown,所以先后弹出以下两个窗口界面:

相关文章
|
安全
职场中千万不要和聪明人较劲
        职场上的“聪明人”其实是很讨人厌的,他们不止装聪明装的厉害,而且喜好指点江山,什么事情都要拿来指导一番。
1065 0
|
5天前
|
存储 JavaScript 前端开发
JavaScript基础
本节讲解JavaScript基础核心知识:涵盖值类型与引用类型区别、typeof检测类型及局限性、===与==差异及应用场景、内置函数与对象、原型链五规则、属性查找机制、instanceof原理,以及this指向和箭头函数中this的绑定时机。重点突出类型判断、原型继承与this机制,助力深入理解JS面向对象机制。(238字)
|
4天前
|
云安全 人工智能 安全
阿里云2026云上安全健康体检正式开启
新年启程,来为云上环境做一次“深度体检”
1568 6
|
5天前
|
安全 数据可视化 网络安全
安全无小事|阿里云先知众测,为企业筑牢防线
专为企业打造的漏洞信息收集平台
1322 2
|
5天前
|
缓存 算法 关系型数据库
深入浅出分布式 ID 生成方案:从原理到业界主流实现
本文深入探讨分布式ID的生成原理与主流解决方案,解析百度UidGenerator、滴滴TinyID及美团Leaf的核心设计,涵盖Snowflake算法、号段模式与双Buffer优化,助你掌握高并发下全局唯一ID的实现精髓。
344 160
|
5天前
|
人工智能 自然语言处理 API
n8n:流程自动化、智能化利器
流程自动化助你在重复的业务流程中节省时间,可通过自然语言直接创建工作流啦。
405 6
n8n:流程自动化、智能化利器
|
7天前
|
人工智能 API 开发工具
Skills比MCP更重要?更省钱的多!Python大佬这观点老金测了一周终于懂了
加我进AI学习群,公众号右下角“联系方式”。文末有老金开源知识库·全免费。本文详解Claude Skills为何比MCP更轻量高效:极简配置、按需加载、省90% token,适合多数场景。MCP仍适用于复杂集成,但日常任务首选Skills。推荐先用SKILL.md解决,再考虑协议。附实测对比与配置建议,助你提升效率,节省精力。关注老金,一起玩转AI工具。
|
14天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
1538 7
|
4天前
|
Linux 数据库
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
本文介绍在CentOS 7.9环境下安装PolarDB-X单机版数据库的完整流程,涵盖系统环境准备、本地Yum源配置、RPM包安装、用户与目录初始化、依赖库解决、数据库启动及客户端连接等步骤,助您快速部署运行PolarDB-X。
246 1
Linux 环境 Polardb-X 数据库 单机版 rpm 包 安装教程
|
8天前
|
人工智能 前端开发 API
Google发布50页AI Agent白皮书,老金帮你提炼10个核心要点
老金分享Google最新AI Agent指南:让AI从“动嘴”到“动手”。Agent=大脑(模型)+手(工具)+协调系统,可自主完成任务。通过ReAct模式、多Agent协作与RAG等技术,实现真正自动化。入门推荐LangChain,文末附开源知识库链接。
669 119