闲话WPF之十九(WPF中的传递事件 [1] )

【传递事件】

WPF在.NET简单事件通知之上添加了很多基础结构。传递事件的设计使得事件可以与元素树一起很好的工作。事件发生后,可以在视觉树和逻辑树自动地进行上下传递,我们不需要添加任何额外的代码。

传递事件使得我们不需要过多关注于视觉树,这样封装对于我们理解WPF的元素合成非常重要。比如,我们点击一个按钮的事件,在点击的时候我们实际上点击的是一个ButtonChrome或者TextBlock,也就是说我们点击的是Button的内容元素。正是因为事件可以沿视觉树传递,Button才发现这个事件,并且可以处理。因此,我们可以给Button的Content当中添加任意的元素,而不会对事件有任何的影响。如果没有这样的事件传递,我们点击Button内的元素时,必须手动编写代码触发Button点击事件。

传递事件的的实现和行为与Dependency属性类似。同样,我们看看如何实现简单的传递事件。多数时候,传递事件并不比普通的.NET事件难。与Dependency属性一样,.NET语言(除了XAML)本身并不明白传递目标。这些支持都是基于WPF API。

public class Button
{
   // 传递的事件
   public static readonly RoutedEvent ClickEvent;

   static Button()
   {
      // 注册事件
      Button.DoubleClickEvent = EventManager.RegisterRoutedEvent(“Click”,
         RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Button));
      …
   }
 
   // .NET事件保证 (可选的)
   public event RoutedEventHandler Click
   {
      add { AddHandler(Button.ClickEvent, value); }
      remove { RemoveHandler(Button.ClickEvent, value); }
   }

   protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
   {
      …
      // 激发事件
      RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));
      …
   }
    …
}

从上面的实现可以看出,事件与Dependency属性有很多相似之处。也是定义一个静态的RoutedEvent成员,同样在静态构造函数里注册事件。为了方便,也包装了一个普通的.NET事件。这里的AddHandler/RemoveHandler不是从DependencyObject派生,而是更高一级的基类System.Windows.UIElement。这两个方法为相应的事件添加/删除一个委派。在OnMouseLeftButtonDown中,我们构造一个事件参数,传入事件源对象this,然后调用RaiseEvent函数。

【事件策略和处理函数】

注册WPF事件时,我们需要为传递事件选择一种策略,这个策略指定了事件在元素树中传递的方式。WPF支持这样三种策略:

   Tunneling:事件首先在根元素激发,然后到达树下的每个元素直到源元素(或者有处理函数处理这个事件终止了传递)。

   Bubbling:事件首先在源元素激发,然后向上直到根元素(或者有处理函数处理这个事件终止了传递。

   Direct:事件只在源元素激发。这与普通的.NET事件一样,除了参与事件触发器。

在上面的例子中,我们注册的事件策略就是Bubbling。

传递事件的处理函数的参数与普通.NET事件一样。第一个参数System.Object表示处理函数依附的元素。第二个的System.EventArgs派生类,提供了如下四个有用的属性:

   Source:逻辑树中激发事件的原始元素。

   OriginalSource:视觉树中激发事件的原始元素。

   Handled:布尔值,表示事件是否被处理。

   RoutedEvent:实际的传递事件对象(比如Button.ClickEvent)。这个对于相同的处理函数处理多个传递事件时非常有用,可以用来区别传递事件。

Source和OriginalSource代表了逻辑树和视觉树对象。这有利于我们进行一些低级控制,但是对于有的事件,不需要区别它们,这两个的值是相同的。

posted @ 2007-01-03 14:06 Yiling Lai 阅读(3503) 评论(16)  编辑 收藏 所属分类: WPF

  回复  引用  查看    
#1楼 2007-01-04 08:47 | 二手的程序员      
问一下大虾 Vista 的Shell 是不是也是托管的
  回复  引用    
#2楼 2007-01-04 11:23 | WPFing [未注册用户]
请问高手一个问题。现在有一个ComboBox,当ComboBoxItem是简单文本的时候,我是通过SelectedItem.Content来获得SelectedItem的值的;如果现在ComboBoxItem是由包含多个控件(比如说CheckBox、TextBlock、TextBox)的DataTemplate定义的,不知道该如何获得ComboBox的SelectedItem中各个控件的值?
  回复  引用  查看    
#3楼 [楼主]2007-01-04 12:07 | Yiling Lai      
@WPFing

Try SelectionBoxItemTemplate
  回复  引用  查看    
#4楼 [楼主]2007-01-04 12:07 | Yiling Lai      
@ 二手的程序员

Both Manage and Unmanage support
  回复  引用    
#5楼 2007-01-04 14:48 | WPFing [未注册用户]
@Yiling Lai
Try SelectionBoxItemTemplate
---------------------------------
Yiling Lai,您好,非常感谢能够给我回复。不过我摸索了半天还是不大会用SelectionBoxItemTemplate,所以能否麻烦您写几行例子代码。另外,ComboBox使用的这种方法,似乎其他的Selector(比如,ListBox、ListView)不能使用。请不吝赐教!
  回复  引用  查看    
#6楼 [楼主]2007-01-05 14:32 | Yiling Lai      
@ WPFing

抱歉,现在才回复你

你的问题我给你一篇文章的连接,也许你就找到方法了,注意要看下面的Comment

http://www.beacosta.com/2005/09/how-can-i-get-listboxitem-from-data.html
  回复  引用  查看    
#7楼 [楼主]2007-01-05 14:45 | Yiling Lai      
  回复  引用    
#8楼 2007-01-05 17:51 | WPFing [未注册用户]
@Yiling Lai
虽然还没来得及研究链接中的文章,但是这里先谢一个!
  回复  引用  查看    
#9楼 2007-04-09 16:08 | xiao_p      
你这里咋这么多广告?

呵呵
  回复  引用    
#10楼 2007-04-20 18:04 | 传奇私服 [未注册用户]
写不很好,顶下
  回复  引用    
#11楼 2007-10-19 09:44 | 紧云 [未注册用户]
写不很好,顶下
  回复  引用    
#12楼 2007-11-07 23:36 | 新开传世私服 [未注册用户]
写不很好,顶下
  回复  引用    
#13楼 2007-11-07 23:37 | 传世私服一条龙 [未注册用户]
v写不很好,顶下
  回复  引用    
#14楼 2007-12-07 20:02 | 传世私服 [未注册用户]
6805
  回复  引用    
#15楼 2007-12-07 20:07 | 征途私服 [未注册用户]
3450

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  博客园首页

  新闻频道

  社区

  小组

  博问

  网摘

  闪存

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      


相关链接: