1. 可传递的消息: WPF的UI是由布局组建和控件构成的树形结构,当这棵树上的某个节点激发出某个事件时,程序员可以选择以传统的直接事件模式让响应者来响应之,也可以让这个事件在UI组件树沿着一定的方向传递且路过多个中转结点,并让这个路由过程被恰当的处理。

2,WPF有两种树,Logical Tree和Visual tree。 LogicTree上,充当叶子的一般都是控件,如果我们把WPF的控件也放在“放大镜下观察”,你会发现每个WPF空间本身也是一棵更细微级别的组件组成的树。用来观察WPF控件的放大镜是我们提到的Blend。如果把Logical Tree衍生至Template组件级别,我们的到的就是Visual Tree。

3,路由事件是沿着Visual Tree传递的。

4.一个事件包括5方面:

  1. 事件的拥有者
  2. 事件
  3. 事件的响应者
  4. 事件处理器
  5. 订阅关系

5. 路由事件的原理: 舍弃直接事件响应者,让不同的控件变成监听者。 而事件拥有者,只负责出发事件。

6,使用WPF内置的路由事件:

Wpf系统的大多数事件都是可路由事件。我们以Button的Click事件来说明路由事件的使用。

1,如何添加监听者:

this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(DefineMethod));

上面这个AddHandler方法来自URElement类。 第一个参数是Button.ClickEvent, 这个叫做路由事件,这里也使用了类似依赖属性包装器的方式。

这里要注意的是,路由事件方法中RoutedEventHandler.Source 是gridRoot. 如果想要得到Button的话,使用RoutedEventHandler.OrigenalSource.

可以在Xaml中使用简化的方法:  <Grid X:Name= “gridRoot”  BackGround=”Lime” Button.Click=”ButtonClicked”>

7,自定义路由事件

三个步骤:

  1. 声明并注册路由事件
  2. 为路由事件添加CLR事件包装
  3. 创建可以激发路由事件的方法

看Code:

public abstract class ButtonBase: ContentControl, ICommandSource
{
public static readonly RoutedEvent ClickEvent =
/*注册路由事件*/
EventManager.RegisterRoutedEvent("Click",RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(ButtonBase)); public event RoutedEventHandler Click
{
add {this.AddHandler(ClickEvent,value)}
Remove {this.RemoveHandler(ClickEvent, value)}
} protected virtual void OnClick()
{
RoutedEventArgs newEvent = new RoutedEventArgs(ButtonBase.ClickEvent,this);
this.RaiseEVent(newEvent);
}
}

路由策略:

  1. Bubble  向上
  2. Tunnel 向下
  3. Direct  模仿CLR直接事件

Demo 2: 实现一个继承自Button的TimeButton类,并添加路由事件

//创建一个RoutedEventArgs类:
class ReportTimeEventArgs:RoutedEventArgs
{
Public ReportTimeEventArgs(RoutedEvent routedEvent, object source)
:Base(routedEvent,source) {} Public DateTime ClickTime {get;set;}
}
class TimeButton : Button
{
//生命和注册路由事件
public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent
("ReportTime",RoutingStrategy.Bubble,typeof(EventHandler<ReportTimeEventArgs>),typeof(TimeButton)); //CLR 事件包装器
public event RoutedEventhandler ReportTime
{
add {this.AddHandler(ReportTimeEvent , value) ;}
remove {this.RemoveHandler(ReportTimeEvent,value);
} //激发路由事件,借用Click事件的激发方法
protected override void OnClick()
{
base.OnClick();
ReportTimeEventArgs args = new ReportTimeEventArgs(ReportTimeEvent, this);
args.ClickTime = DateTime.Now;
this.RaiseEvent(args);
}
//看看怎么使用吧
       local:TimeButton.ReportTime = “ReportTimeHandler”;
           //ReportTimeEvent 路由事件处理器
           private void ReportTimeHandler(objecet sender, ReportTimeEventArgs e)
           {
                FrameworkElement element  = sender as FrameworkElement;
                string timeStr  = e.ClickTime.ToLongTimeString();
                string content = string.Format(“{0}  到达 {1}”,timeStr,element.Name);
                this.listBox.Items.Add(content);
           }
8, 如何让路由事件停止传播:
      使用e.handled 如果e.handled==true,则停止传递。
9. RoutedEventArgs的Source和OriginalSource
Source是logicTree的消息源头,而OriginalSource是visualTree上的源头。
如果一个Button是在UserControl中,那么Source应该是UserControl , OriginalSource 应该是 Button/
10. 事件也附加----深入浅出附加事件
那些类拥有附加事件
  • Binding类: SourceUpdated事件、 TargetUpdated事件
  • Mouse类: MouseEnter事件、MouseLeave事件、MouseDown事件、MouseUp事件等
  • Keyboard类: KeyDown事件、KeyUp事件
对比路由事件会发现: 附加事件不具备显示在用户界面上的能力。
看一个Demo:设计一个Student类,如果Student实例的Name属性值发生了变化就激发一个路由事件,然后使用界面元素来捕捉这个事件。
public class Student
{
public static readonly RoutedEvent NameChangedEvent = EventManager.ResisterRoutedEvent
( "NameChanged",routingStrategy.Bubble,typeof(RoutedEventHandler),typeof(Student)); public int Id {get;set;}
public string Name {get;set;}
}
然后我们设计一个button. 
<Button  x:Name = "button1" Content="OK"  Width="80" Height="80"   Click="Button_Click">
 看看后台代码 
   //添加事件监听器
  this.gridMain.AddHandler(Student.nameChangedEvent, new RoutedEventHandler(this.DtudentnameChangedHandler))
   //Click 事件处理器
   private void Button_Click(objcet sender, RoutedEventArgs e)
{
Student stu = new Student() {Id=10,Name="Tim"};
stu.Name="Tom";
//准备事件消息并发送路由事件
        //附加事件宿主是没有办法发送路由事件的,要借助一个FrameworkElement来RaiseEvent(arg)
        //其中RoutedEventArgs 有两个参数,一个附加事件,一个是实例。
RoutedEventArgs arg = new RoutedEventArgs(Student.NameChangedEvent,stu);
this.button1.RaiseEvent(arg);
} //Grid 捕捉到nameChangedEvent后的处理器
private void StudentNameChangedHandler(object sender, RoutedEventArgs e)
{
MessageBox.Show((e.OriginalSource as Student).Id.ToString());
}
11. 事件也附加2
其实上面那个例子已经是一个附加文件了,但是微软的官方文档约定要为这个附加事件添加一个CLR包装以便XAML编辑器识别并进行只能提示。 但是,因为Student类不是UIElement的派生类,因为不具备Addhandler和 RemoveHandler这两个方法,所以不能使用CLR属性作为包装器:
  • 为目标UI元素附加事件侦听器的包装器是一个名为Add*Handler的public static 方法,星号代表事件名称
public class Student
{
//声明并定义路由事件
public static readonly RoutedEvent NameChangedEvent = EventManager.RegisterRouredEvent
("NameChanged",RoutingStrategy.Bubble,typeof(RoutedEventHandler),typdof(Student)); //为界面元素添加路由事件侦听
public static void AddNameChangedHandler(DependencyObject d,RoutedEventHandler h)
{
UIElement e = d as UIElement;
if(e!=null)
{
e.AddHandler(Student.NameChangedEvent, h);
}
} public static voidRemoveNameChangedHandler(DependencyObject d,RoutedEventHandler h)
{
UIElement e = d as UIElement;
if(e!=null)
{
e.AddHandler(Student.NameChangedEvent, h);
}
} public int Id {get;set;}
public string Name {get;set;}
}

public Window1()

{

Student.AddNameChangedHandler(this.gridMain, new RoutedEventHandler(this.StudnetnameChagnedHandler));

}

再次理解一下附加事件:

UIElement类是路由事件宿主与附加事件宿主的分水岭,不但是因为从UIElemtn类开始才具备了界面上显示的能力,还因为RaiseEvent、AddHandler和RemoveHandler 这些方法也定义在UIElement类中。 如果在一个非UIElement派生类中注册了路由事件,则这个类的实例既不能自己激发,也无法自己侦听此路由事件。

转载:http://www.cnblogs.com/zhaoyun2007/archive/2012/12/06/2804581.html

WPF 学习笔记 路由事件的更多相关文章

  1. WPF学习之路由事件

    原文:http://www.cnblogs.com/lxy131/archive/2010/08/10/1796754.html WPF中新添加了一种事件---路由事件 路由事件与一般事件的区别在于: ...

  2. WPF学习笔记-用Expression Design制作矢量图然后导出为XAML

    WPF学习笔记-用Expression Design制作矢量图然后导出为XAML 第一次用Windows live writer写东西,感觉不错,哈哈~~ 1.在白纸上完全凭感觉,想象来画图难度很大, ...

  3. WPF 学习笔记-在WPF下创建托盘图标

    原文:WPF 学习笔记-在WPF下创建托盘图标 首先需要在项目中引用System.Windows.Forms,System.Drawing; using System; using System.Co ...

  4. WPF 学习笔记-设置属性使窗口不可改变大小

    原文:WPF 学习笔记-设置属性使窗口不可改变大小 调整Windows下的ResizeMode属性: ResizeMode = NoResize Resize属性是控制Windows是否可以改变大小, ...

  5. 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果

    学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcE ...

  6. WPF学习笔记(8):DataGrid单元格数字为空时避免验证问题的解决

    原文:WPF学习笔记(8):DataGrid单元格数字为空时避免验证问题的解决 如下图,在凭证编辑窗体中,有的单元格不需要数字,但如果录入数字后再删除,会触发数字验证,单元格显示红色框线,导致不能执行 ...

  7. WPF中的路由事件(转)

    出处:https://www.cnblogs.com/JerryWang1991/archive/2013/03/29/2981103.html 最近因为工作需要学习WPF方面的知识,因为以前只关注的 ...

  8. Angular6 学习笔记——路由详解

    angular6.x系列的学习笔记记录,仍在不断完善中,学习地址: https://www.angular.cn/guide/template-syntax http://www.ngfans.net ...

  9. WPF原理剖析——路由事件

    一.路由事件与传统事件传统事件的触发者和处理者是紧密相连的,而路由事件则不是,路由事件允许一个元素的事件有另外的元素触发.也即就是说路由事件的拥有者和响应者之间没有显示的订阅关系.事件的拥有者只负责激 ...

随机推荐

  1. MIT6.828课程JOS在macOS下的环境配置

    本文将介绍如何在macOS下配置MIT6.828 JOS实验的环境. 写JOS之前,在网上搜寻JOS的开发环境,很多博客和文章都提到"不是32位linux就不好配置,会浪费大量时间在配置环境 ...

  2. c# List集合中First、Last、Single方法使用

    操作符 如果源序列是空的 源序列只包含一个元素 源序列包含多个元素 First 抛异常 返回该元素 返回第一个元素 FirstOrDefault 返回default(TSource) 返回该元素 返回 ...

  3. JS查错小工具-三生有幸【推荐】

    H5和CSS语言在开发者官网上都有在线查错工具,同样的,更加复杂的JavaScript也需要一个查错工具,(别指望DreamWeaver了,debug功能做的太垃圾,还不如Firefox自带的强..) ...

  4. UX是什么?

    UX(用户体验),操作过安卓手机或者苹果手机的系统吧?那么操作过程的整体体验就叫UX,而操作过程中所看到的界面颜色啦,图案,字体大小啦等等都属于UI设计,而交互设计(Interaction Desig ...

  5. 1st_homework_SE--四则运算题目生成器

    0x00 Code 查询源代码及README请点此 0x01 需求分析 实现一个自动生成小学四则运算题目的命令行程序. 0x02 功能设计 主要功能为: 接受用户输入以便知道要出多少道题目python ...

  6. 英语词典Alpha版本发布说明

    Alpha版本发布说明 功能: ·简洁的应用界面,不被无良的广告弹窗影响  ·功能直接,在需要查词时及时出现,没有每日一句精选文章等杀了你的流量,在学习过程中更加专注! ·采用金山词霸API,提供发音 ...

  7. javascript:12种JavaScript MVC框架之比较

    Gordon L. Hempton是西雅图的一位黑客和设计师,他花费了几个月的时间研究和比较了12种流行的JavaScript MVC框架,并在博客中总结了每种框架的优缺点,最终的结果是,Ember. ...

  8. 分布式一致性算法Raft

    什么是分布式一致性? 我们先来看一个例子: 我们有一个单节点node,这个节点可以是数据库,也可以是一台服务器,当client向node发送data时,X节点收到data,记录下来 由此可见对于单个节 ...

  9. Hibernate第三篇【主配置文件、映射文件、复合主键映射】

    前言 目前已经学了如何搭建Hibernate的开发环境,以及Hibernate对应的API了-在快速入门还没讲解的就是配置文件是怎么配置的.因此,本博文主要讲解主配置文件以及映射配置文件.. 主配置文 ...

  10. OJ周末题

    字符串分割 字符统计 记票统计