出处:https://www.cnblogs.com/JerryWang1991/archive/2013/03/29/2981103.html

最近因为工作需要学习WPF方面的知识,因为以前只关注的是B/S架构的东西,可是没想到参加工作的第一个项目竟然是C/S架构的WPF方面的开发,因为Web方面主要是请求响应模型,没有事件这个东西,在学习webform时虽然是基于事件模型的也有没有认真的研究事件,因为它已经逐渐被mvc或者其他方式(比如ashx和jquery easyui等类似的)替代,现在是CS架构了,需要把这块知识补上。

1、简单的事件模型

事件的前身是消息,消息的本质就是一组数据记录这要执行的操作,然后消息处理函数根据消息的数据执行相应的操作,那么在消息处理函数中就充斥这大量的判断或者switch,这样对于大型应用程序的开发带来了不少麻烦。为了简单的开发微软封装了一套简单的事件模型。以前了解过window form的应该都知道,当托一个按钮到窗体后然后双击按钮就可以在.cs代码自动生成有关事件的代码,这就是一个简单的事件模型

事件模型包括一下几个部分,我们对应到一个winform程序的Demo中如下:

事件的拥有者:就是按钮:button1

事件:就是button1.Click,在Form1.cs中

事件的处理器就是这个方法button1_Click

订阅关系:也就是说事件和事件处理器如何建立联系的呢:

打开Form1.Designer.cs找答案

 this.button1.Click += new System.EventHandler(this.button1_Click);

这里就建立了事件和事件处理器的联系,当然一个事件我们也可以定义多个处理器相应。

最后一个响应者:就是窗体本身

2、路由事件模型

传统的简单事件模型中,在消息激发是将消息通过事件订阅的然后交给事件的相应者,事件的相应者使用事件的处理器来做出相应,这样就存在一个问题,用户控件内部的事件就不能被外界订阅,因为事件的宿主必须能够直接访问到事件的响应者。

路由事件的事件拥有者和事件的相应者之间则没有直接的显式订阅关系,事件的拥有者则只负责激发事件,事件将有谁相应它并不知道,事件的响应者则有事件的监听器,针对事件进行监听,当有此类事件传递至此事件响应者就使用事件处理器来相应事件并决定此事件是否继续传递。比如像上一个程序中的,点击“点我”以后事件就开始激发了,然后事件就会在控件树上进行传递,事件的响应者安装了监听器,当监听到这个事件进行响应,并决定这个事件是否继续传递。

如果当事件在某个节点处理以后,不想让它继续传递,可以把它标记为“已处理”,就会停止路由,所有的路由事件都共享一个公共的事件数据基类 RoutedEventArgs。RoutedEventArgs 定义了一个采用布尔值的 Handled 属性。把事件设为已处理只要把Handled属性设为true即可

Xaml代码:

<Window x:Class="RouteEventWpfDemo.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="MainWindow" Height="350" Width="525"><Grid x:Name="GridA"><Grid x:Name="GridB"><Grid x:Name="GridC"><Button Canvas.Left="101" Canvas.Top="68" Content="Button" Height="23" Name="ButtonA" Width="75" /></Grid></Grid></Grid>
</Window>

xaml的交互逻辑代码

  public partial class MainWindow : Window{/// <summary>/// 主窗口构造器/// </summary>public MainWindow(){InitializeComponent();//为GridA添加Button.ClickEvent监听this.GridA.AddHandler(Button.ClickEvent,new RoutedEventHandler(this.ButtonA_Click));//为GridB添加Button.ClickEvent监听this.GridB.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.ButtonA_Click));//为GridC添加Button.ClickEvent监听this.GridC.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.ButtonA_Click));}private void ButtonA_Click(object sender, RoutedEventArgs e){MessageBox.Show(((Grid)sender).Name);}

3、自定义路由事件

自定义路由事件大体需要三个步骤:

1、声明并注册路由事件

2、为路由事件添加CLR事件包装

3、创建可以激发路由事件的方法

Xaml代码

<Window x:Class="MyRouteEventWpfDemo.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:MyRouteEventWpfDemo"local:TimeButton.ReportTime="ReportTimeHandler"Title="MainWindow" Height="350" Width="525"><Grid x:Name="GridA" local:TimeButton.ReportTime="ReportTimeHandler"><Grid x:Name="GridB" local:TimeButton.ReportTime="ReportTimeHandler"><Grid x:Name="GridC" local:TimeButton.ReportTime="ReportTimeHandler"><StackPanel x:Name="StackPanelA" local:TimeButton.ReportTime="ReportTimeHandler"><ListBox x:Name="listBox"/><local:TimeButton x:Name="btnTime" Content="时间"  local:TimeButton.ReportTime="ReportTimeHandler" /></StackPanel></Grid></Grid></Grid>
</Window>

自定义的ReportTimeEventArgs

 /// <summary>/// 可以记录时间的RoutedEventArgs/// </summary>public class ReportTimeEventArgs : RoutedEventArgs{public ReportTimeEventArgs(RoutedEvent routedEvent, object source): base(routedEvent, source){ }/// <summary>/// 记录点击时间/// </summary>public DateTime ClickTime { get; set; }}

定义一个时间Button

/// <summary>/// 自定义个一个时间控件/// </summary>public class TimeButton : Button{//声明并注册路由事件/** 1、第一个参数ReportTime 为路由事件的名称* 2、第二个参数是路由事件的策略,包括Bubble冒泡式,Tunnel隧道式,Direct直达式(和直接事件类似)* 3、第三个参数用于指定事件处理器的类型* 4、第四个参数用于指定事件的宿主是哪一种类型*/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);}        //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);}}
}

xaml的交互逻辑代码

    /// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void ReportTimeHandler(object sender, ReportTimeEventArgs e){FrameworkElement element = (FrameworkElement)sender;string timeStr = e.ClickTime.ToString("HH:mm:ss");string content = string.Format("{0}==>到达{1}", timeStr, element.Name);this.listBox.Items.Add(content);}}

4、附加事件

在wpf中还有一种事件附加事件,像前面说的路由事件它的事件宿主都是我们可以看到的界面元素,但是附加事件不具备显式在用户界面上的能力,比如一个文本框的改变,鼠标的按下,键盘的按下这些事件都是附加事件的例子

还是上面的例子我们给他加上颜色改变事件

在TimeButton类中添加如下代码

        /// <summary>/// 声明颜色属性/// </summary>public string Color { get; set; }/// <summary>/// 声明并注册颜色改变路由事件/// </summary>public static readonly RoutedEvent ColorChangedEvent = EventManager.RegisterRoutedEvent("ColorChanged", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));/// <summary>/// 添加颜色改变事件/// </summary>/// <param name="d"></param>/// <param name="e"></param>public static void AddColorChangedHandler(DependencyObject d, RoutedEventHandler e){UIElement ui = (UIElement)d;if (ui != null){ui.AddHandler(TimeButton.ColorChangedEvent, e) ;}}/// <summary>/// 删除颜色改变事件/// </summary>/// <param name="d"></param>/// <param name="e"></param>public static void RemoveColorChangedHandler(DependencyObject d, RoutedEventHandler e){UIElement ui = (UIElement)d;if (ui != null){ui.RemoveHandler(TimeButton.ColorChangedEvent, e);}}

MainWindow.cs改为

public partial class MainWindow : Window{public MainWindow(){InitializeComponent();//btnTime添加路由事件监听TimeButton.AddColorChangedHandler(this.btnTime, new RoutedEventHandler(this.ColorChangedHandler));}private void ReportTimeHandler(object sender, ReportTimeEventArgs e){FrameworkElement element = (FrameworkElement)sender;string timeStr = e.ClickTime.ToString("HH:mm:ss");string content = string.Format("{0}==>到达{1}", timeStr, element.Name);this.listBox.Items.Add(content);this.btnTime.Color = "123";//准备消息传给路由事件RoutedEventArgs args = new RoutedEventArgs(TimeButton.ColorChangedEvent, this.btnTime);//引发事件this.btnTime.RaiseEvent(args);}private void ColorChangedHandler(object sender, RoutedEventArgs e){MessageBox.Show((e.OriginalSource as TimeButton).Color);}}

参考:http://msdn.microsoft.com/zh-cn/library/ms742806.aspx

http://msdn.microsoft.com/zh-cn/library/bb613550.aspx

----转载请注明出处http://www.cnblogs.com/JerryWang1991/ 谢谢!

WPF中的路由事件(转)相关推荐

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

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

  2. WPF中的鼠标事件详解

    WPF中的鼠标事件详解 Uielement和ContentElement都定义了十个以Mouse开头的事件,8个以PreviewMouse开头的事件,MouseMove,PreviewMouseMov ...

  3. WPF 学习笔记 路由事件

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

  4. WPF学习之路由事件

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

  5. WPF之定义路由事件 http://www.51zxw.net/study.asp?vip=8963801

    [url=http://www.51zxw.net/study.asp?vip=8963801] 学IT必看,[经典] [基础] [进阶] [实践 ] [成神][超神][返璞归真] [/url] us ...

  6. WPF 中的 loaded 事件和 Initialized 事件

    在 WPF 中, 控件有 Loaded 和 Initialized 两种事件. 初始化和加载控件几乎同时发生, 因此这两个事件也几乎同时触发. 但是他们之间有微妙且重要的区别. 这些区别很容易让人误解 ...

  7. WPF中对鼠标事件转换为命令处理模式的鼠标位置参数传递及EventArgs传递

    在WPF中使用命令模型,对于实现ICommandSource的元素来讲,比较方便,对于未实现ICommandSouce的元素来讲可以利用Blend中提供的行为来解决.通常情况下,命令对象可以传递命令参 ...

  8. WPF中路由事件的传播

    路由事件(RoutedEvent)是WPF中新增的事件,使用起来与传统的事件差别不大, 但传播方式是完全不同的. 路由事件的传播方式 通过RoutingStrategy来定义传播的方式 public ...

  9. WPF,Silverlight与XAML读书笔记第八 - WPF新概念之三路由事件

    说明:本系列基本上是<WPF揭秘>的读书笔记.在结构安排与文章内容上参照<WPF揭秘>的编排,对内容进行了总结并加入一些个人理解. 路由事件是专门设计用于在元素树中使用的事件. ...

最新文章

  1. 119. Leetcode 115. 不同的子序列 (动态规划-子序列问题)
  2. 在Delphi中关于UDP协议的实现
  3. 关于sqoop增量导入oracle的数据到HDFS的出现的错误总结
  4. Java运算符及录入
  5. dubbo之rmi协议使用
  6. 简单帅气的折纸机器人_新型电磁喷雾可将任何物体变成机器人,有望在生物学领域应用...
  7. 数据仓库3级范式(3NF)基础
  8. MFC:应用程序无法正常启动(0xc0150002)
  9. RS232(串口线)转RJ45(网线)
  10. office各种格式文件对应的MIME Type/http:Content-Type
  11. 89C51最小系统典型应用
  12. 实习每日总结_20161212
  13. 深度学习第三天-卷积神经网络(CNN):乳腺癌识别
  14. COALESCE()函数 一个非常有用的函数
  15. python123实验七答案_2020年智慧树嵌入式系统与实验第七单元章节测试答案
  16. koa2如何允许跨域
  17. java中sql查重跟去重_sql中查重和去重
  18. 目录扫描工具DirBuster
  19. HBuilderX配置Git插件
  20. 可视化网盘系统的设计与实现过程记录

热门文章

  1. access课程均不及格_access 第二章 查询 练习题 -
  2. 理解有符号数和无符号数的区别
  3. python控制电脑关机_Python利用智能音箱语音控制电脑开关机
  4. 同软件多个线程设置不同ip_多线程--面试知识
  5. c语言代码表白_用微信表情翻译表白,程序员的小浪漫,赶紧Get起来
  6. java 时间衰减函数_TensorFlow实现指数衰减学习率的方法
  7. 网格自适应_Abaqus网格重划自适应技术
  8. linux 部署项目
  9. BeanUtils注意事项
  10. react实现汉堡_利用 React 高阶组件实现一个面包屑导航