WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。

1.WPF内置路由事件

WPF中的大多数事件都是路由事件,WPF有3中路由策略:

具体不多讲,单需要注意的是WPF路由事件是沿着VIsualTree传递的。VisualTree与LogicalTree的区别在于:LogicalTree的叶子节点是构成用户界面的控件(xaml紧密相关),而VisualTree要连控件中的细微结构也算上。VisualTree是LogicalTree的扩展。

reference: Understanding the Visual Tree and Logical Tree in WPF

下面给出一个使用WPF内置路由事件的例子:

<Window x:Class="WPFRoutedEvent.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="Grid1" Margin="10" Background="AliceBlue" MouseLeftButtonDown="Grid1_MouseLeftButtonDown"> <StackPanel Background="BurlyWood" Height="200" x:Name="StackPanel1" Button.Click="ButtonInStackPanel_Click" MouseLeftButtonDown="StackPanel1_MouseLeftButtonDown"> <Button x:Name="Button1" Content="RoutedEvent" Click="Button1_Click" /> </StackPanel> </Grid> </Window>

View Code

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input; namespace WPFRoutedEvent { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //Grid订阅Button的Click事件 Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click)); } private void Button1_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Button Clicked."); // //e.Handled = true;  } private void ButtonInStackPanel_Click(object sender, RoutedEventArgs e) { MessageBox.Show("StackPanel Clicked."); } private void ButtonInGrid_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Grid Clicked."); } private void Grid1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { MessageBox.Show("Grid Mouse Left button down."); } private void StackPanel1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { MessageBox.Show("StackPanel Mouse Left button down."); } } }

Button的Click事件是一个路由事件,分别在StackPanel中和Grid中订阅这个事件并进行相应的处理,分别用xaml代码和C#代码如下:

Click="Button1_Click"

Button.Click="ButtonInStackPanel_Click"

Grid1.AddHandler(Button.ClickEvent, new RoutedEventHandler(ButtonInGrid_Click));

StackPanel的MouseLeftButtonDown也是一个路由事件,也可以叫“附加事件”。其实“附加事件”也是路由事件,只是个文字游戏,为什么还要另外起个名字呢?原来路由事件的宿主都是那些拥有可视化实体的界面元素;而附加事件则不具备显示在用户界面上的能力。

常见的附加事件有:

Binding类:SourceUpdated事件、TargetUpdated事件。

Mouse类:MouseEnter事件、MouseLeave事件、MouseDown事件、MouseUp事件等。

Keyboard类:KeyDown事件、KeyUp事件等。

Grid和StackPanel中均如下订阅:

MouseLeftButtonDown="StackPanel1_MouseLeftButtonDown"

程序运行如下:

2.自定义路由事件

前面DebugLZQ写过一篇博文,内容是关于自定义CLR事件的,参考:.NET自定义事件小结。下面来自定义一个WPF路由事件,各位博友可以比较下两者的异同。

创建自定义路由事件大体可以分为三个步骤:

(1)声明并注册路由事件

(2)为路由事件添加CLR事件包装

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

下面我们自定义一个WPF路由事件,我们给事件携带个参数,为此需要创建一个RoutedEventArgs类的派生类。如下:

using System;
using System.Windows;namespace MyRoutedEvent { //事件参数 class ReportTimeRoutedEventArgs:RoutedEventArgs { public ReportTimeRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public DateTime ClickTime { get; set; } } }

然后,创建一个Button类的派生类并按前面的步骤为其添加路由事件:

using System;
using System.Windows.Controls;
using System.Windows; namespace MyRoutedEvent { class TimeButton:Button { //声明和注册路由事件\ public static readonly RoutedEvent ReportTimeRoutedEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeRoutedEventArgs>), typeof(TimeButton)); //CLR事件包装 public event RoutedEventHandler ReportTime { add { this.AddHandler(ReportTimeRoutedEvent, value); } remove { this.RemoveHandler(ReportTimeRoutedEvent, value); } } //激发路由事件,借用Click事件的激发方法 protected override void OnClick() { base.OnClick();//保证Button原有功能正常使用,Click事件被激发  ReportTimeRoutedEventArgs args = new ReportTimeRoutedEventArgs(ReportTimeRoutedEvent, this); args.ClickTime = DateTime.Now; this.RaiseEvent(args);//UIElement及其派生类  } } }

下面是程序界面的XAML代码,看下如何消费这个路由事件:

<Window x:Class="MyRoutedEvent.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MyRoutedEvent" Title="MainWindow" Height="350" Width="525"> <Grid x:Name="grid1" local:TimeButton.ReportTime="TimeButton_ReportTime"><!----> <Grid x:Name="grid2"> <Grid x:Name="grid3"> <StackPanel x:Name="stackPanel1"> <ListBox x:Name="listBox1"/> <local:TimeButton Width="200" Height="200" Background="Aquamarine" ReportTime="TimeButton_ReportTime" /><!----> </StackPanel> </Grid> </Grid> </Grid> </Window>

事件处理的后台代码如下:

using System.Windows;namespace MyRoutedEvent
{/// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void TimeButton_ReportTime(object sender, ReportTimeRoutedEventArgs e)//注意参数  { listBox1.Items.Add(e.ClickTime.ToLongTimeString()+"DebugLZQ"); } } }

假如我如果想在后台代码中消费定义的路由事件,该如何做呢?

  /// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();this.grid1.AddHandler(TimeButton.OnReportTimeRoutedEvent, new RoutedEventHandler(MainWindow_MEvent));this.grid1.AddHandler(TimeButton.OnReportTimeRoutedEvent, new RoutedEventHandler(TimeButton_ReportTime1));//监听OnReportTimeRoutedEvent的路由事件
            }private void TimeButton_ReportTime(object sender, ReportTimeRoutedEventArgs e){listBox1.Items.Add(e.ClickTime.ToLongTimeString() + "DebugLZQ");}private void TimeButton_ReportTime1(object sender, RoutedEventArgs e){ReportTimeRoutedEventArgs ss = e as ReportTimeRoutedEventArgs;//这里使用了一个转换,父类转换程子类的引用,只有转换了,才能被AddHandler调用。
listBox1.Items.Add(ss.ClickTime.ToLongTimeString() + "DebugLZQ");}void MainWindow_MEvent(object sender, RoutedEventArgs e){MessageBox.Show("dddd");}}

程序运行效果如下:

小结:UIElement类是路由事件和附加事件的分水岭,因为从UIElement类开始才具备了再界面上显示的能力,也因为RaiseEvent、AddHandler和RemoveHandler这些方法也定义在UIElement类中。附加事件也只能算是路由事件的一种用法而不是一个新的概念,其本质还是路由事件。

WPF自定义路由事件(二)相关推荐

  1. WPF Demo18 路由事件

    using System.Windows;namespace 路由事件2 {public class Student{声明并定义路由事件//public static readonly RoutedE ...

  2. WPF中路由事件的传播

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

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

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

  4. WPF 学习笔记 路由事件

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

  5. WPF学习之路由事件

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

  6. 《深入浅出WPF》笔记——事件篇

    如果对事件一点都不了解或者是模棱两可的话,建议先去看张子阳的委托与事件的文章(比较长,或许看完了,也忘记看这一篇了,没事,我会原谅你的)http://www.cnblogs.com/JimmyZhan ...

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

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

  8. WPF系列学习之三(路由事件)

    路由事件实际上以一上 列三种方式出现.     1.与普通的.net事件类似的直接路由事件.它们起源于一个元素,并且不传递给其他元素.例如:MouseEnter事件.     2.在包含层次中向上传递 ...

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

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

  10. WPF中MsgBox的弹出会中断路由事件的传递

    在WPF的Tunnel(Preview)路由事件中用MessageBox.Show弹出对话框后,会中断后续的Bubbling事件.根据MSFT的解释是,MessageBox弹出时获取到了焦点,导致路由 ...

最新文章

  1. 解决“错误 D8016 “/ZI”和“/Gy-”命令行选项不兼容 ”问题
  2. PHP (20140506)
  3. Python爬虫开发:post请求(用户登录)
  4. AX中对Programmable section的动态控制
  5. 10_java之继承和抽象类
  6. C# CKEditor、CKFinder集成使用
  7. 美媒:小米新浪达成合作 采取行动对抗腾讯
  8. [luogu P3128][USACO15DEC]Max Flow [LCA][树上差分]
  9. java 保留字符串数字的位数,不够前面补0
  10. OpenCL将数组从内存copy到显存
  11. tab+easyui datagrid无法正常显示
  12. Spark Streaming实现WordCount
  13. linux 内存pss,内存耗用:VSS/RSS/PSS/USS
  14. windows下3389端口开启和连接
  15. VC6LineNumber完美破解版
  16. Excel中阳历转阴历
  17. Java输入1~12之间的整数,显示该月份的英语单词及这个月属第几季度。
  18. html如何防止内部撑开,父div没有被撑开,该怎么解决?_html/css_WEB-ITnose
  19. Java11 ZGC 和 Java12 Shenandoah 介绍:苟日新、日日新、又日新
  20. 18 副为程序员定制的对联,总有一副适合你...流泪

热门文章

  1. ORACLE OUI 中断 do not have sufficient permissions /u01/app/oraInventory
  2. Ubuntu Linux 环境变量PATH设置
  3. SQL简单基础(1)
  4. 编程大讲坛:C#核心开发技术从入门到精通pdf
  5. Java--UI--弹出对话框
  6. 汇编学习笔记(1)基础知识
  7. [转载]网页栅格系统研究(1):960的秘密
  8. 使用数据绑定实现多窗口间的数据同步
  9. smbinning包:R语言下的分箱处理工具
  10. Lesson 08 for Plotting in R for Biologists