Windows Phone中的路由事件-以ListBox控件為例


  今天我們來介紹一下Windows Phone中的路由事件,以ListBox控件為例。

  首先我們來熟悉一下路由事件的概念。

  路由事件是具有更強傳播能力的事件,他們可以在元素樹中向上冒泡和向下隧道傳播,並且沿着傳播路徑被事件處理程序處理。路由事件經常以冒泡路由事件和隧道路由事件的形式出現,冒泡路由事件是在元素樹中向上傳播的一種事件,觸發事件的源會把事件傳遞給他的父元素,他的父元素又會將事件繼續向上傳遞,直到傳遞到元素樹的頂端,或者有着特殊的邏輯處理。稍后會給大家詳細講述冒泡路由事件的工作方式。隧道路由事件的工作方式和冒泡路由事件相同,但方向相反。他是在元素樹中向下傳播的一種事件,觸發事件的源的會尋找他的子元素,然后把事件傳遞給他。隧道路由事件通常比較容易辨認,因為他們都以單詞Preview開頭。隧道路由事件總是在冒泡路由事件之前被觸發。今天我們的重點是冒泡路由事件。

              
  由於是講Windows phone中的路由事件,那就要講一下觸摸屏設備所特有的事件--觸摸事件。在Windows phone中 觸摸事件主要有3種,比較簡單,分別是ManipulationStarted事件,他是在用戶的手指觸摸到屏幕時觸發的事件。ManipulationDelta事件,他是用戶的手指在屏幕上滑動式觸發的事件。ManipulationCompleted事件,他是用戶的手指離開屏幕時觸發的事件。值得注意的是,以上三種觸摸事件都是冒泡路由事件。

                


  好,下面讓我們來結合程序詳細介紹一下Windows phone中的路由事件。

  新建一個Windows Phone應用程序,在內容Grid中添加以下XAML代碼。

 

 1 <ListBox  x:Name="listBox"
 2                       ManipulationStarted="listBox_ManipulationStarted" 
 3                       ManipulationCompleted="listBox_ManipulationCompleted"
 4                       >
 5                 <ListBoxItem x:Name="listBoxItem1"
 6                     ManipulationStarted="listBoxItem1_ManipulationStarted"  
 7                     ManipulationCompleted="listBoxItem1_ManipulationCompleted">
 8                     <TextBlock x:Name="textBlock1" FontSize="30" 
 9                                    Text="文本一文本一文本一" 
10                                    ManipulationStarted="textBlock1_ManipulationStarted" 
11                                    ManipulationCompleted ="textBlock1_ManipulationCompleted"/>
12                 </ListBoxItem>
13                 <ListBoxItem x:Name="listBoxItem2"
14                     ManipulationStarted="listBoxItem2_ManipulationStarted"  
15                     ManipulationCompleted="listBoxItem2_ManipulationCompleted">
16                     <TextBlock x:Name="textBlock2" FontSize="30"
17                                    Text="文本二文本二文本二" 
18                                    ManipulationStarted="textBlock2_ManipulationStarted" 
19                                    ManipulationCompleted="textBlock2_ManipulationCompleted"/>
20                 </ListBoxItem>
21             </ListBox>

 

  這段代碼比較簡單,包括一個listbox控件,和兩個listboxitem,每個listboxitem的內容也比較簡單,就是一行文本,我們給每個控件都分別注冊了ManipulationStarted事件和ManipulationCompleted事件。

  這是完成后的手機界面:

          

  接下來,我們添加后台的事件處理程序,上代碼。

  首先添加一個名字空間:

1 using System.Diagnostics;

  然后是事件處理程序的代碼:

 1 private void listBox_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
 2         {
 3             Debug.WriteLine("OUT PUT: listBox_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
 4         }
 5 
 6         private void listBox_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
 7         {
 8             Debug.WriteLine("OUT PUT: listBox_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
 9         }
10 
11         private void listBoxItem1_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
12         {
13             Debug.WriteLine("OUT PUT: listBoxItem1_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
14         }
15 
16         private void listBoxItem1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
17         {
18             Debug.WriteLine("OUT PUT: listBoxItem1_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
19         }
20 
21         private void textBlock1_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
22         {
23             Debug.WriteLine("OUT PUT: textBlock1_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
24         }
25 
26         private void textBlock1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
27         {
28             Debug.WriteLine("OUT PUT: textBlock1_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
29         }
30 
31         private void listBoxItem2_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
32         {
33             Debug.WriteLine("OUT PUT: listBoxItem2_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
34         }
35 
36         private void listBoxItem2_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
37         {
38             Debug.WriteLine("OUT PUT: listBoxItem2_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
39         }
40 
41         private void textBlock2_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
42         {
43             Debug.WriteLine("OUT PUT: textBlock2_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
44         }
45 
46         private void textBlock2_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
47         {
48             Debug.WriteLine("OUT PUT: textBlock2_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
49         }

  每個事件處理程序都是類似的,他的功能是在調試時的輸出窗口里打印一行文本,這樣我們就可以清晰的看到每個事件處理的順序。

  運行程序,並單擊第一個ListBoxItem,我們發現輸出窗口會打印一下文字:  

   

 

  我們首先觀察前3行文字,他是一個完整的冒泡路由過程,從觸發事件的TextBlock,再到ListBoxItem,最后到元素樹的頂級元素ListBox終止(其實ListBox並不是真正的頂級元素,真正的頂級元素應該是phone:PhoneApplicationPage控件,但由於沒有對phone:PhoneApplicationPage控件的觸摸事件進行處理,所以在這里是無法顯示的,目前我們姑且認為ListBox控件就是元素樹的頂級元素)。我們再來看最后一行文字,比較奇怪,ManipulationCompleted事件並沒有完成一個完整的冒泡路由過程,這是怎么回事呢?我們在此留下一個懸念,稍后會給大家解釋。

  我們繼續完善代碼。

  首先在ListBox中添加一個ListBoxItem。

 1 <ListBoxItem x:Name="listBoxItem3"
 2                              ManipulationStarted="listBoxItem3_ManipulationStarted"
 3                              ManipulationCompleted="listBoxItem3_ManipulationCompleted">
 4                     <CheckBox x:Name="checkBox"
 5                              ManipulationStarted="checkBox_ManipulationStarted"
 6                              ManipulationCompleted="checkBox_ManipulationCompleted"
 7                              >
 8                         <TextBlock x:Name="textBlock3" Text="文本三文本三文本三文本三文本三"
 9                                    ManipulationStarted="textBlock3_ManipulationStarted"
10                                    ManipulationCompleted="textBlock3_ManipulationCompleted"/>
11                     </CheckBox>
12                 </ListBoxItem>

  這個ListBoxItem的內容是一個CheckBox控件,CheckBox控件中又包含了一行文本。

  這是添加完成后的手機界面。

        

  接下來是事件處理程序的代碼。

 1  private void listBoxItem3_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
 2         {
 3             Debug.WriteLine("OUT PUT: listBoxItem3_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
 4         }
 5 
 6         private void listBoxItem3_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
 7         {
 8             Debug.WriteLine("OUT PUT: listBoxItem3_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
 9         }
10 
11         private void checkBox_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
12         {
13             Debug.WriteLine("OUT PUT: checkBox_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
14         }
15 
16         private void checkBox_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
17         {
18             Debug.WriteLine("OUT PUT: checkBox_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
19         }
20 
21         private void textBlock3_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
22         {
23             Debug.WriteLine("OUT PUT: textBlock3_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString());
24         }
25 
26         private void textBlock3_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
27         {
28             Debug.WriteLine("OUT PUT: textBlock3_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString());
29             
30         }

  和以前也是一樣的,也是在調試時的輸出窗口里打印一行文本。

  運行程序,並單擊新添加的帶有CheckBox的ListBoxItem,我們會看到輸出窗口會發生變化。  

  

    由於ListBoxItem中包含了一個帶有文本的CheckBox控件,所以元素樹的層次增加了一層。我們可以清晰的看到,和上一次不一樣的是,不論是ManipulationStarted事件還是ManipulationCompleted事件都完成了完整的冒泡路由傳遞,這又是為什么呢?

  為了進一步解釋這個問題,我們進一步完善代碼。

  首先給ListBox控件注冊一個SelectionChanged事件。

1 <ListBox  x:Name="listBox"
2                       ManipulationStarted="listBox_ManipulationStarted" 
3                       ManipulationCompleted="listBox_ManipulationCompleted"
4                       SelectionChanged="listBox_SelectionChanged" 
5                      >

  然后給SelectionChanged事件添加事件處理程序。

1 private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
2         {
3             Debug.WriteLine("OUT PUT: listBox_SelectionChanged in {0}", DateTime.Now.ToLongTimeString());
4         }

  該事件處理程序功能和原來是類似的。

  運行程序,先后點擊只有文本的ListBoxItem和帶有CheckBox控件的ListBoxItem,我們注意對比兩者的不同。

  點擊只有文本的ListBoxItem。

  

  單擊帶有CheckBox控件的ListBoxItem   

  

  我們發現當單擊只有文本的ListBoxItem的時候,在TextBlock控件的ManipulationCompleted事件后,觸發了ListBox的SelectionChanged事件,而單擊帶有CheckBox控件的ListBoxItem的時候並沒有觸發ListBox的SelectionChanged事件,事實上這就是問題的關鍵所在。  

  當ListBoxItem中包含着對單擊或觸摸有特殊處理的控件(Button、CheckBox、RatioButton)的時候,不會觸發ListBox的SelectionChanged事件,會將事件繼續向上傳遞。而ListBoxItem中僅僅有自身對單擊或觸摸沒有特殊處理的控件(TextBlock Image),就會觸發ListBox的SelectionChanged事件,而SelectionChanged就不會向上繼續傳遞了。因為已經到了頂級元素ListBox那里。這就是冒泡路由事件的向上傳遞被中斷的原因。  

  好了,到現在大家對應該windows phone中的路由事件應該已經有了一個大致的了解,希望大家能自己建立一個示例程序,試驗一下其他控件在ListBox中的表現,這樣能夠更加深刻的理解路由事件。

  相關視頻請參考:http://v.youku.com/v_show/id_XMzc4NTc2ODIw.html  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM