Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1050275
  • 博文数量: 403
  • 博客积分: 10272
  • 博客等级: 上将
  • 技术积分: 4407
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:22
文章分类

全部博文(403)

文章存档

2012年(403)

分类: 嵌入式

2012-04-10 19:31:32

今天我们来介绍一下Windows Phone中的路由事件,以ListBox控件为例。

  首先我们来熟悉一下路由事件的概念。

  路由事件是具有更强传播能力的事件,他们可以在元素树中向上冒泡和向下隧道传播,并且沿着传播路径被事件处理程序处理。路由事件经常以冒泡路由事件和隧道路由事件的形式出现,冒泡路由事件是在元素树中向上传播的一种事件,触发事件的源会把事件传递给他的父元素,他的父元素又会将事件继续向上传递,直到传递到元素树的顶端,或者有着特殊的逻辑处理。稍后会给大家详细讲述冒泡路由事件的工作方式。隧道路由事件的工作方式和冒泡路由事件相同,但方向相反。他是在元素树中向下传播的一种事件,触发事件的源的会寻找他的子元素,然后把事件传递给他。隧道路由事件通常比较容易辨认,因为他们都以单词Preview开头。隧道路由事件总是在冒泡路由事件之前被触发。今天我们的重点是冒泡路由事件。

              
  由于是讲Windows phone中的路由事件,那就要讲一下触摸屏设备所特有的事件--触摸事件。在Windows phone中 触摸事件主要有3种,比较简单,分别是ManipulationStarted事件,他是在用户的手指触摸到屏幕时触发的事件。ManipulationDelta事件,他是用户的手指在屏幕上滑动式触发的事件。ManipulationCompleted事件,他是用户的手指离开屏幕时触发的事件。值得注意的是,以上三种触摸事件都是冒泡路由事件。

                


  好,下面让我们来结合程序详细介绍一下Windows phone中的路由事件。

  新建一个Windows Phone应用程序,在内容Grid中添加以下XAML代码。

 

<ListBox x:Name="listBox" ManipulationStarted="listBox_ManipulationStarted" ManipulationCompleted="listBox_ManipulationCompleted" > <ListBoxItem x:Name="listBoxItem1" ManipulationStarted="listBoxItem1_ManipulationStarted" ManipulationCompleted="listBoxItem1_ManipulationCompleted"> <TextBlock x:Name="textBlock1" FontSize="30" Text="文本一文本一文本一" ManipulationStarted="textBlock1_ManipulationStarted" ManipulationCompleted ="textBlock1_ManipulationCompleted"/> ListBoxItem> <ListBoxItem x:Name="listBoxItem2" ManipulationStarted="listBoxItem2_ManipulationStarted" ManipulationCompleted="listBoxItem2_ManipulationCompleted"> <TextBlock x:Name="textBlock2" FontSize="30" Text="文本二文本二文本二" ManipulationStarted="textBlock2_ManipulationStarted" ManipulationCompleted="textBlock2_ManipulationCompleted"/> ListBoxItem> ListBox>

 

  这段代码比较简单,包括一个listbox控件,和两个listboxitem,每个listboxitem的内容也比较简单,就是一行文本,我们给每个控件都分别注册了ManipulationStarted事件和ManipulationCompleted事件。

  这是完成后的手机界面:

          

  接下来,我们添加后台的事件处理程序,上代码。

  首先添加一个名字空间:

using System.Diagnostics;

  然后是事件处理程序的代码:

private void listBox_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: listBox_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void listBox_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: listBox_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void listBoxItem1_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem1_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void listBoxItem1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem1_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock1_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock1_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock1_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock1_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void listBoxItem2_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem2_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void listBoxItem2_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem2_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock2_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock2_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock2_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock2_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); }

  每个事件处理程序都是类似的,他的功能是在调试时的输出窗口里打印一行文本,这样我们就可以清晰的看到每个事件处理的顺序。

  运行程序,并单击第一个ListBoxItem,我们发现输出窗口会打印一下文字:  

   

 

  我们首先观察前3行文字,他是一个完整的冒泡路由过程,从触发事件的TextBlock,再到ListBoxItem,最后到元素树的顶级元素 ListBox终止(其实ListBox并不是真正的顶级元素,真正的顶级元素应该是phone:PhoneApplicationPage控件,但由于 没有对phone:PhoneApplicationPage控件的触摸事件进行处理,所以在这里是无法显示的,目前我们姑且认为ListBox控件就是 元素树的顶级元素)。我们再来看最后一行文字,比较奇怪,ManipulationCompleted事件并没有完成一个完整的冒泡路由过程,这是怎么回 事呢?我们在此留下一个悬念,稍后会给大家解释。

  我们继续完善代码。

  首先在ListBox中添加一个ListBoxItem。

<ListBoxItem x:Name="listBoxItem3" ManipulationStarted="listBoxItem3_ManipulationStarted" ManipulationCompleted="listBoxItem3_ManipulationCompleted"> <CheckBox x:Name="checkBox" ManipulationStarted="checkBox_ManipulationStarted" ManipulationCompleted="checkBox_ManipulationCompleted" > <TextBlock x:Name="textBlock3" Text="文本三文本三文本三文本三文本三" ManipulationStarted="textBlock3_ManipulationStarted" ManipulationCompleted="textBlock3_ManipulationCompleted"/> CheckBox> ListBoxItem>

  这个ListBoxItem的内容是一个CheckBox控件,CheckBox控件中又包含了一行文本。

  这是添加完成后的手机界面。

        

  接下来是事件处理程序的代码。

private void listBoxItem3_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem3_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void listBoxItem3_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: listBoxItem3_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void checkBox_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: checkBox_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void checkBox_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: checkBox_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock3_ManipulationStarted(object sender, ManipulationStartedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock3_ManipulationStarted in {0}", DateTime.Now.ToLongTimeString()); } private void textBlock3_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) { Debug.WriteLine("OUT PUT: textBlock3_ManipulationCompleted in {0}", DateTime.Now.ToLongTimeString()); }

  和以前也是一样的,也是在调试时的输出窗口里打印一行文本。

  运行程序,并单击新添加的带有CheckBox的ListBoxItem,我们会看到输出窗口会发生变化。  

  

    由于ListBoxItem中包含了一个带有文本的CheckBox控件,所以元素树的层次增加了一层。我们可以清晰的看到,和上一次不一 样的是,不论是ManipulationStarted事件还是ManipulationCompleted事件都完成了完整的冒泡路由传递,这又是为什 么呢?

  为了进一步解释这个问题,我们进一步完善代码。

  首先给ListBox控件注册一个SelectionChanged事件。

<ListBox x:Name="listBox" ManipulationStarted="listBox_ManipulationStarted" ManipulationCompleted="listBox_ManipulationCompleted" SelectionChanged="listBox_SelectionChanged" >

  然后给SelectionChanged事件添加事件处理程序。

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

  该事件处理程序功能和原来是类似的。

  运行程序,先后点击只有文本的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中的表现,这样能够更加深刻的理解路由事件。

  相关视频请参考:  

阅读(1432) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~