Wpf自定义路由事件
创建自定义路由事件大体可以分为三个步骤:
①声明并注册路由事件。
②为路由事件添加CLR事件包装。
③创建可以激发路由事件的方法。
以ButtonBase类中代码为例展示这3个步骤:
public abstract class ButtonBase:ContentControl,ICommandSource
{
//声明并注册路由事件。
public static readonly RoutedEvent ClickEvent=EventManager.RegisterRoutedEvent("Click",RoutedStrategy.Bubble,typeof(RoutedEventHandler),typeof(ButtonBase));
//为路由事件添加CLR事件包装器。
pubic event RoutedEventHandler Click
{
add{this.AddHandler(ClickEvent,Value);}
remove{this.REmoveHandler(ClickEvent,Value);}
}
//激发路由事件的方法,此方法在用户单击鼠标时会被Windows系统调用
protected virtual void OnClick()
{
RoutedEventArgs newEvent=new RoutedEventArgs(ButtonBase.ClickEvent,this);
this.RaiseEvent(new Event);
}
}
理解EventManager.RegisterRoutedEvent方法的四个参数:
第一个参数:
参数为String类型,被称为路由事件的名称。应与RoutedEvent变量的前缀和CLR事件包装器的名称一致。
第二个参数:
①Buddle,冒泡式:路由事件有事件的激发着出发向它的上级容器一层一层路由,直至最外层容器(Window或者Page)。因为是有树的底端向顶端移动,所以这种策略被形象的命名为“冒泡式”。
②Tunnel,隧道式:事件的路由方向正好与Bubble策略相反。
③Direct,直达式:模仿CLR直接事件,直接将事件消息送达事件处理器。
第三个参数:
用于指定事件处理器类型。事件处理器的返回值类型和参数列表必须与此参数指定的委托保持一致,不然会导致在编译时抛出异常。
第四个参数:
用于指定路由事件的宿主(拥有者)是哪儿个类型。
自己动手创建一个路由事件,这个事件的用途是报告事件发生的时间。
“兵马未动,粮草先行”。为了让事件消息能携带按钮被单击时的时间。先创建一个RoutedEventArgs类的派生类。
//用于承载时间消息的事件参数
class ReportTimeEventArgs:RoutedEventArgs
{
public ReportTimeEventArgs(RoutedEvent routedEvent,object source)
:base(routedEvent,source){}
public DateTime ClickTime{get;set;}
}
然后创建一个Button类的派生类并按前述步骤为其添加路由事件。
class TimeButton:Button
{
//声明和注册路由事件
public static Readonly RoutedEvent ReportTimeEvent=EventManager.RegisterManager
("ReportTime",RoutingStrategy.Bubbl,typeof(EventHandler<ReportTimeArgs>),typeof(TimeButton));
//为路由事件添加CLR事件包装器
public event RoutedEventHanler ReportTime
{
add{AddHandler(ReportTimeEvent,value);}
remove{RemoveHandler(ReportTimeEvent,value);}
}
//激发路由事件,借用Click事件的激发事件
protected override void OnClick()
{
base.OnClick();
ReportTimeEventArgs args=new ReportTimeEventArgs(ReportEvent,this);
args.ClickTime=DateTime.Now;
this.RaiseEvent(args);
}
}
//下面是程序界面XAML代码
<Window x:Class="Wpf8.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf8"
local:TimeButton.ReportTime="ReportTimeHandler"
Title="Window1" Height="300" Width="300">
<Grid x:Name="grid_1" local:TimeButton.ReportTime="ReportTimeHandler">
<Grid x:Name="grid_2" local:TimeButton.ReportTime="ReportTimeHandler">
<Grid x:Name="grid_3" local:TimeButton.ReportTime="ReportTimeHandler">
<StackPanel x:Name="stackPanel_1" local:TimeButton.ReportTime="ReportTimeHandler">
<ListBox x:Name="listBox"></ListBox>
<local:TimeButton x:Name="timeButton" Width="80" Height="80" Content="报时" local:TimeButton.ReportTime="ReportTimeHandler"></local:TimeButton>
</StackPanel>
</Grid>
</Grid>
</Grid>
</Window>
在UI界面上,以Window为根,套了三层Grid和一层StackPanel。最里面放置了一个ListBox和一个TimeButton。从最内层的TimeButton到最外层的Window都侦听着TimeButton.ReportTimeEvent这个路由事件。并用ReportTimeHandler方法来响应这个事件。ReportTimeHandler的代码如下:
//ReportTimeEvent路由事假处理器
private void ReportTimeHandler(object 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);
}
运行程序,单击按钮。


RoutedEvenArgs的Source与OriginalSource
路由事件的消息包含在RouteEventArgs实例中。RoutedEventArgs有两个属性Source和OriginalSource。这两个属性都表示路由事件传递的起点。只不过Source表示的是LogicalTree上的消息源头,而OriginalSource则表示VisualTree上的源头。
示例:
创建一个用户控件:
<UserControl x:Class="Wpf8.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border BorderBrush="Orange" BorderThickness="3" CornerRadius="5">
<Button x:Name="innerButton" Width="80" Height="80" Content="OK"></Button>
</Border>
</UserControl>
在主窗体中添加用户控件。
<Window x:Class="Wpf8.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf8"
Title="Window2" Height="180" Width="300">
<Grid>
<local:MyUserControl x:Name="myUserControl" Margin="10"/>
</Grid>
</Window>
后台代码:
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
//为主窗体添加对Button.Click事件的侦听。
this.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.Button_Click));
}
//路由事件处理器。
private void Button_Click(object sender, RoutedEventArgs e)
{
string strOriginalSource = string.Format("VisualTree start point:{0},type is {1}",
(e.OriginalSource as FrameworkElement).Name,e.OriginalSource.GetType().Name);
string strSource = string.Format("LogicalTree start point:{0},type is {1}",
(e.Source as FrameworkElement).Name,e.Source.GetType().Name);
MessageBox.Show(strOriginalSource+"\r\n"+strSource);
}
}
Button.Click路由事件是从MyUserControl的innerButton发出来的,在主窗体中,myUserControl是LogicalTree的末端结点,所以e.source就是myUserControl;而窗体的VisualTree则包含了myUserControl的内部结构。所以使用e.OriginalSource可以获得innerButton.

Wpf自定义路由事件的更多相关文章
- WPF:自定义路由事件的实现
路由事件通过EventManager,RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数:通过RaiseEvent方法来 ...
- WPF自定义路由事件(二)
WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件. 1.WPF内置路由事件 WPF ...
- 细说WPF自定义路由事件
WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件. 1.WPF内置路由事件 W ...
- WPF 自定义路由事件
如何:创建自定义路由事件 首先自定义事件支持事件路由,需要使用 RegisterRoutedEvent 方法注册 RoutedEvent C#语法 public static RoutedEvent ...
- WPF自定义路由事件(一)
首先自定义事件支持事件路由,需要使用 RegisterRoutedEvent 方法注册 RoutedEvent C#语法 public static RoutedEvent RegisterRoute ...
- WPF 自定义路由事件 与 附加路由事件
为student添加附件事件
- WPF自学入门(四)WPF路由事件之自定义路由事件
在上一遍博文中写到了内置路由事件,其实除了内置的路由事件,我们也可以进行自定义路由事件.接下来我们一起来看一下WPF中的自定义路由事件怎么进行创建吧. 创建自定义路由事件分为3个步骤: 1.声明并注册 ...
- WPF路由事件三:自定义路由事件
与依赖项属性类似,WPF也为路由事件提供了WPF事件系统这一组成.为一个类型添加一个路由事件的方式与为类型添加依赖项属性的方法类似,添加一个自定义路由事件的步骤: 一.声明路由事件变量并注册:定义只读 ...
- WPF的路由事件、冒泡事件、隧道事件(预览事件)
本文摘要: 1:什么是路由事件: 2:中断事件路由: 3:自定义路由事件: 4:为什么需要自定义路由事件: 5:什么是冒泡事件和预览事件(隧道事件): 1:什么是路由事件 WPF中的事件为路由事件,所 ...
随机推荐
- 【转】Adnroid4.0 签名混淆打包(conversion to dalvik format failed with error 1)
原文网址:http://jojol-zhou.iteye.com/blog/1220541 自己的解决方法:关闭Eclipse,再开启Eclipse就可以. 最新Eclipse3.7+android ...
- HDU 5926 Mr. Frog's Game 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
Mr. Frog's Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...
- cmd命令行设置环境变量
http://blog.sciencenet.cn/blog-51026-566742.html 1.查看当前所有可用的环境变量:输入 set 即可查看. 2.查看某个环境变量:输入 “set 变量名 ...
- 关于JNI程序中引用另外一个lib
我最近在写一个j2se的程序,我用的是开源的org.amse.ys.zip包里的代码,这部分代码是在FBReaderJ里抽取的,但是其中包含了一些native的方法,需要用的zlib库,而FBRead ...
- mysql使用mysqldump导出数据出错
mysqldump -hlocalhost -uroot -p123456 student_info jssypk > c:/databackup.sql 导出表结构 mysqldump - ...
- hdu4281 区间dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4283 #include<iostream> #include<algorithm&g ...
- 找出Active Directory架构操作主机方法!
- SQL Server阻止了对组件xp_cmdshell过程的解决方案 分类: SQL Server 2015-03-05 08:31 305人阅读 评论(0) 收藏
SQL Server阻止了对组件xp_cmdshell过程的解决方案 错误描述:SQL Server阻止了对组件'xp_cmdshell'的过程'sys.xp_cmdshell'的访问.因为此组件已作 ...
- UML 的基本组成
UML 是由UML构造块.规则.通用机制三部分组成的.而UML构造块由建模元素(事物).关系和图组成. 建模元素 建模元素是对模型中最具有代表性的成分的抽象.一般情况下,将建模元素分为结构元素.行为元 ...
- storyBoard使用介绍
storyBoard使用介绍 转载地址:http://www.2cto.com/kf/201210/161737.html 一 .简述 Storyboard是你可以用来定义用户界面的一种新的方式,像x ...