天天看點

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) 

//通過e.Handled設定為ture表示路由事件已處理攔截了事件, 

//不必冒泡到父對象的LayoutRoot_MouseLeftButtonDown去處理。 

MessageBox.Show("引發事件的對象名是:" + ellipse.Name + ",路由事件被攔截"); 

e.Handled = true; 

#endregion 

        在滑鼠左鍵點選事件中的e.OriginalSource可以擷取到觸發事件的源對象。

        在此執行個體中,我們點選圓ellipseFirst的時候,它沒有任何事件處理程式,于是冒泡路由政策發生作用,此次點選事件由父對象的LayoutRoot_MouseLeftButtonDown事件處理程式進行處理。于是彈出以下界面:

<a target="_blank" href="http://blog.51cto.com/attachment/201203/183616586.jpg"></a>

        當我們點選圓ellipseSecond的時候,它自身有一個事件處理程式,于是首先執行它自身的左鍵點選處理程式ellipse2_MouseLeftButtonDown,彈出以下界面:

<a target="_blank" href="http://blog.51cto.com/attachment/201203/183550274.jpg"></a>

        二、注冊冒泡路由事件

        在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檔案代碼如下:

&lt;Grid Width="200" Height="200" x:Name="GridB" HorizontalAlignment="Right" Background="Aqua"&gt; 

&lt;Ellipse Height="44" HorizontalAlignment="Left" Fill="Coral" Name="ellipseThird" 

&lt;Ellipse Height="44" HorizontalAlignment="Left" Fill="DarkSalmon" Margin="0,71,0,0" 

Name="ellipseFourth" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" 

        在這裡我們建立了一個名為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) 

//處理這次事件的對象 

//擷取到觸發事件的對象 

        在上一段代碼中我們在控件的Loaded事件中為GridB注冊了一個事件處理程式名為:GridB_MouseLeftButtonDown。注意我們在使用AddHandle注冊這個程式的時候,設定了handledEventsToo 為Ture,意味着我們不管子控件(ellipseThird和ellipseFourth)的自身事件處理程式中是否設定e.Handled是否為 Ture,我們都要執行父控件的事件處理程式GridB_MouseLeftButtonDown。反之如果我們設定handledEventsToo為False,則根據子控件的e.Handled是否為Ture來決定是否冒泡路由到父控件處理。

        下面我們來看看點選ellipseThird的時候彈出以下界面:

<a target="_blank" href="http://blog.51cto.com/attachment/201203/183440901.jpg"></a>

        下面我們來看看點選ellipseFourth的時候,因為設定handledEventsToo 為Ture,不管子控件(ellipseThird和ellipseFourth)的自身事件處理程式中是否設定e.Handled是否為Ture,我們 都要執行父控件的事件處理程式GridB_MouseLeftButtonDown,是以先後彈出以下兩個視窗界面:

本文轉自程興亮 51CTO部落格,原文連結:http://blog.51cto.com/chengxingliang/822566