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派生类中注册了路由事件,则这个类的实例既不能自己激发,也无法自己侦听此路由事件。

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

WPF 学习笔记 路由事件相关推荐

  1. WPF学习之路由事件

    最近因为工作需要学习WPF方面的知识,因为以前只关注的是B/S架构的东西,可是没想到参加工作的第一个项目竟然是C/S架构的WPF方面的开发,因为Web方面主要是请求响应模型,没有事件这个东西,在学习w ...

  2. WPF学习笔记(数据绑定篇3)

    接上回的<WPF学习笔记(数据绑定篇2)>,继续 BindValidation 此示例演示了: 如何使用错误模板: 使用样式显示错误信息: 如何在校验发生异常时执行回调: 首先,你可以看见 ...

  3. WPF学习笔记(7):DataGrid中数字自定义格式显示

    WPF学习笔记(7):DataGrid中数字自定义格式显示 原文:WPF学习笔记(7):DataGrid中数字自定义格式显示 DataGrid中数据显示如下图,数据格式比较杂乱.希望达到以下要求:(1 ...

  4. JavaScript 学习笔记 - 挂载事件 Demo

    JavaScript 学习笔记 - 挂载事件 Demo 例子 addEventListener 监听事件 挂载事件的同时带上参数 dispatchEvent 触发事件 removeEventListe ...

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

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

  6. 了解 WPF 中的路由事件和命令

    目录 路由事件概述 WPF 元素树 事件路由 路由事件和组合 附加事件 路由命令概述 操作中的路由命令 命令路由 定义命令 命令插入 路由命令的局限 避免命令出错 超越路由命令 路由处理程序示例 要想 ...

  7. Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 IhandleT

    Caliburn.Micro学习笔记目录 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现 ...

  8. WPF学习笔记(三)

    1.1 事件概括 第一节中我们给窗体添加了一个按钮,不过好像Button点个几下也只有些发光样式的变化,什么你还把系统皮肤去掉了?算了承认下确实够寒碜,那让我们再动动手. 1.1.1 路由事件简述 p ...

  9. WPF学习笔记-第二周【基本笔刷】

    书接上回,这一次,讲的是WPF中的基本笔刷,由于是菜鸟,就不多说了,继续帖示例代码:) 第一部份 代码 第二章 基本笔刷 第一个 示例 VaryTheBackgroud P38  1     #reg ...

最新文章

  1. 干活干累了,刷一道题,一天保底两道,一年也就差不多刷完了 ----------7. Reverse Integer...
  2. mysql top limit_MySQL中如何实现select top n ----Limit
  3. 大剑无锋之如何查看一个java进程的堆内存使用情况(jps,jstack,jmap)【面试推荐】
  4. postman安装_Postman插件的应用与实战(二)
  5. 只会python怎么挣钱_业余学python有用吗
  6. 26 CO配置-控制-产品成本控制-成本对象控制-期末结算-定义结果分析版本
  7. 【LCS】POJ1458Common Subsequence
  8. 你为什么用微信,不用 QQ ?
  9. 阶段3 2.Spring_08.面向切面编程 AOP_3 spring基于XML的AOP-编写必要的代码
  10. DP题目推荐合集(洛谷/UVa)
  11. ​​​​​​​国民经济行业分类(GB/T 4754—2017)
  12. 蜂巢输入法android,讯飞输入法“蜂巢II”输入模型 内核提速便捷实用
  13. 松翰单片机--SN8F5702学习笔记(七)TIMER0、TIMER1
  14. 28 JS基础之--String包装数据类型方法总结
  15. selectpicker的使用方法
  16. 谷歌tts android手机自带引擎,自动下载android TTS引擎
  17. 360浏览器极速版 v7.5.3.182 官方正式版_HTM5浏览器
  18. 后台管理页面左侧导航栏
  19. ROS下如何将GPS数据在卫星地图显示(两种开源方法)
  20. 镜头能看多远,人眼能看多远

热门文章

  1. Golang实践录:我的工具包
  2. u-boot移植随笔:u-boot启动流程简图
  3. 《转》ReentrantLock实现原理深入探究
  4. 【算法】剑指 Offer 50. 第一个只出现一次的字符
  5. 【Flink】checkpoint storage at checkckpoint coordinator No route host from xx to xx:9000
  6. 【es】ES RestHighLevelClient 请求报错:Connection reset by peer
  7. 【Elasticsearch】bulk default_local reports failures when export documents
  8. 95-136-070-源码-Operator-扩展有状态的operators
  9. 95-264-040-源码-重启恢复-本地恢复
  10. 【Spark】reduceByKey和GroupByKey