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,所以先后弹出以下两个窗口界面:

相关文章
|
2月前
|
开发框架 前端开发 JavaScript
使用Winform开发自定义用户控件,以及实现相关自定义事件的处理
使用Winform开发自定义用户控件,以及实现相关自定义事件的处理
|
10月前
|
小程序 JavaScript 前端开发
微信小程序(三十一)自定义watch监听属性
微信小程序并没有为我们在普通的页面中提供类似vue中watch类似的监听属性。 还是那句话,人家没给,你还想用,自己定义一个。
276 0
|
小程序
微信小程序 - 父组件绑定子组件外传事件通信
微信小程序 - 父组件绑定子组件外传事件通信
117 0
|
JavaScript
WebApi入门第三章(事件介绍及注册事件 )
WebApi入门第三章(事件介绍及注册事件 )
125 0
WebApi入门第三章(事件介绍及注册事件 )
C#(三十一)之自定义事件
本篇内容记录了自定义事件、事件继承。
114 0
C#(三十一)之自定义事件
|
JavaScript C#
C#(WPF)去除事件中注册的事件处理方法!
在WPF中,移除一个事件中已经注册的处理方法,看似简单,实际还是很痛苦的一件事情。因为C#的灵活性,定义事件的方法也是多种多样。我自己定义了一个事件: public event EventHandler TestEvent; 当我想注销这个事件上注册的所有方法的时候,我可以按如下的方法进行 Delegate[] dels = TestEvent.
3999 0
|
.NET C# 开发框架
WPF的路由事件、冒泡事件、隧道事件(预览事件)
原文:WPF的路由事件、冒泡事件、隧道事件(预览事件) 本文摘要: 1:什么是路由事件; 2:中断事件路由; 3:自定义路由事件; 4:为什么需要自定义路由事件; 5:什么是冒泡事件和预览事件(隧道事件); 1:什么是路由事件     WPF中的事件为路由事件,所谓路由事件,MSDN定义如下:     功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。
1761 0
|
.NET C# 开发框架
WPF - 善用路由事件
原文:WPF - 善用路由事件   在原来的公司中,编写自定义控件是常常遇到的任务。但这些控件常常拥有一个不怎么好的特点:无论是内部还是外部都没有使用路由事件。那我们应该怎样宰自定义控件开发中使用路由事件?我们将在这篇短文中对该问题进行讨论。
903 0
|
C#
WPF 路由事件
原文:WPF 路由事件 最近想封装一个关于手势的控件,但是由其他的控件覆盖之后发现不能触发,据说是有一些事件在定义的时候就处理过e.Handle了。 定义的时候就处理了,就是为了控件能够正常的工作,别如Button.MouseDown什么的。
930 0