WPF自定义路由事件(二)
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>


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自定义路由事件(二)的更多相关文章
- WPF:自定义路由事件的实现
路由事件通过EventManager,RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数:通过RaiseEvent方法来 ...
- 细说WPF自定义路由事件
WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件. 1.WPF内置路由事件 W ...
- WPF 自定义路由事件
如何:创建自定义路由事件 首先自定义事件支持事件路由,需要使用 RegisterRoutedEvent 方法注册 RoutedEvent C#语法 public static RoutedEvent ...
- Wpf自定义路由事件
创建自定义路由事件大体可以分为三个步骤: ①声明并注册路由事件. ②为路由事件添加CLR事件包装. ③创建可以激发路由事件的方法. 以ButtonBase类中代码为例展示这3个步骤: public a ...
- WPF自定义路由事件(一)
首先自定义事件支持事件路由,需要使用 RegisterRoutedEvent 方法注册 RoutedEvent C#语法 public static RoutedEvent RegisterRoute ...
- WPF 自定义路由事件 与 附加路由事件
为student添加附件事件
- WPF自学入门(四)WPF路由事件之自定义路由事件
在上一遍博文中写到了内置路由事件,其实除了内置的路由事件,我们也可以进行自定义路由事件.接下来我们一起来看一下WPF中的自定义路由事件怎么进行创建吧. 创建自定义路由事件分为3个步骤: 1.声明并注册 ...
- WPF路由事件三:自定义路由事件
与依赖项属性类似,WPF也为路由事件提供了WPF事件系统这一组成.为一个类型添加一个路由事件的方式与为类型添加依赖项属性的方法类似,添加一个自定义路由事件的步骤: 一.声明路由事件变量并注册:定义只读 ...
- WPF 之路由事件和附加事件(六)
一.消息驱动与直接事件模型 事件的前身是消息(Message).Windows 是消息驱动的系统,运行其上的程序也遵循这个原则.消息的本质就是一条数据,这条消息里面包含着消息的类别,必要的时候还记 ...
随机推荐
- nginx限制ip访问(转)
一.服务器全局限IP #vi nginx.conf allow 10.57.22.172; #允许的IP deny all; 二.站点限IP #vi vhosts.conf 站点全局限IP ...
- Jenkins配置基于角色的项目权限管理
转自: http://www.cnblogs.com/gao241/archive/2013/03/20/2971416.html, 版权归原作者. 本文将介绍如何配置jenkins,使其可以支持基于 ...
- 深入理解JVM(一)——JVM内存模型
JVM内存模型 Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区. ...
- Oracle NID工具修改数据库DBID、数据库名称、数据库实例名
DBID是数据库的唯一标识符,在一些特殊场合会涉及到DBID的相关内容,本篇文章的目的是演示将DB_NAME的值从ORCL修改为ORCL1. 一.查看当前的环境 [oracle@oracledb ad ...
- JAVA Spring boot相关技巧
1. 注册多实例.@Scope("prototype") 2. 手工方式获取注册的实例. @Autowired private ServletContext servletCont ...
- Google 发布的15个 Android 性能优化典范
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...
- swift4.0 对 afn 进行二次封装
先将 afn 用pod导入到 工程中 创建一个类 ZHttpTools 继承自 AFHTTPSessionManager 一般我们不希望网络请求同时有多个存在,所以我们将这个工具类 设计成单例 代 ...
- Java注解应用,自定义注解映射实现方案说明.
插件结构如图: 注册模块定义了三个:用于实体与表映射的注解,用于属性到表字段的映射,用于映射时过滤掉的注解. 1.用于实体与表映射的注解 package com.dobby.plugins.annot ...
- golang----GC的实现原理
Golang从1.5开始引入了三色GC, 经过多次改进, 当前的1.9版本的GC停顿时间已经可以做到极短.停顿时间的减少意味着"最大响应时间"的缩短, 这也让go更适合编写网络服务 ...
- CentOS 7 安装SVN并整合HTTP访问
#!/bin/bash## -------------------------------------------------## 安装svn并整合http访问## ----------------- ...