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 

來源:http://www.th7.cn/Program/wp7/2012/04/10/69103.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章