《WPF程序设计指南》读书笔记——第9章 路由输入事件
1.使用路由事件
路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。通俗地说,路由事件会在可视树(逻辑树是其子集)上,上下routed,如果哪个节点上订阅了事件,就会被触发。
路由事件的规则有三种:
(1)冒泡;由事件源向上沿视觉树传递一直到根元素。如 MouseDown
(2)直接;只有事件源才有机会响应事件,某个元素引发事件后,不传递到其他元素
(3)隧道;从元素树的根部调用事件处理程序并依次向下深入直到事件源。 一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的。隧道事件常常被称为Preview事件。如 PreviewMouseDown
可以通过 e.handled = true 来停止路由。
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Documents; namespace LY.ExamineRoutedEvents
{
public class ExamineRoutedEvents : Application
{
static readonly FontFamily fontfam = new FontFamily("宋体");
const string strformat = "{0,-30},{1,-15},{2,-15},{3,-15}";
StackPanel stackOutput;
DateTime dtLast;
[STAThread]
public static void Main()
{
ExamineRoutedEvents app = new ExamineRoutedEvents();
app.Run();
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Window win = new Window();
win.Title = "Examine Routed Events";
//建立Grid
Grid grid = new Grid();
win.Content = grid;
//建立三行
RowDefinition rowdef = new RowDefinition();
rowdef.Height = GridLength.Auto;
grid.RowDefinitions.Add(rowdef); rowdef = new RowDefinition();
rowdef.Height = GridLength.Auto;
grid.RowDefinitions.Add(rowdef); rowdef = new RowDefinition();
rowdef.Height = new GridLength(100, GridUnitType.Star);
grid.RowDefinitions.Add(rowdef); //建立button,加入到grid
Button btn = new Button();
btn.HorizontalAlignment = HorizontalAlignment.Center;
btn.Padding = new Thickness(24);
btn.Margin = new Thickness(24);
grid.Children.Add(btn);
//建立textblock,加入button
TextBlock text = new TextBlock();
text.FontSize = 24;
text.Text = win.Title;
btn.Content = text;
//建立标题,显示在ScrollViewer
TextBlock textHeadings = new TextBlock();
textHeadings.FontFamily = fontfam;
textHeadings.Inlines.Add(new Underline(new Run(string.Format(strformat,
"Routed Events", "Sender", "Source", "OriginalSource"))));
grid.Children.Add(textHeadings);
Grid.SetRow(textHeadings, 1);
//加入Scorllviewer
ScrollViewer scroll = new ScrollViewer();
grid.Children.Add(scroll);
Grid.SetRow(scroll, 2);
//建立Stackpanel,放入Scorllviewer
stackOutput = new StackPanel();
scroll.Content = stackOutput;
//新增事件处理器
UIElement[] els = { win, grid, btn, text };
foreach (UIElement el in els)
{
// Keyboard
el.PreviewKeyDown += AllPurposeEventHandler;
el.PreviewKeyUp += AllPurposeEventHandler;
el.PreviewTextInput += AllPurposeEventHandler;
el.KeyDown += AllPurposeEventHandler;
el.KeyUp += AllPurposeEventHandler;
el.TextInput += AllPurposeEventHandler; // Mouse
el.MouseDown += AllPurposeEventHandler;
el.MouseUp += AllPurposeEventHandler;
el.PreviewMouseDown += AllPurposeEventHandler;
el.PreviewMouseUp += AllPurposeEventHandler; // Stylus
el.StylusDown += AllPurposeEventHandler;
el.StylusUp += AllPurposeEventHandler;
el.PreviewStylusDown += AllPurposeEventHandler;
el.PreviewStylusUp += AllPurposeEventHandler;
//Window,Grid,Textblock类没有click事件,所以用在ButtonBase类中定义的AddHandler方法
el.AddHandler(Button.ClickEvent,
new RoutedEventHandler(AllPurposeEventHandler));
}
win.Show();
} void AllPurposeEventHandler(object sender, RoutedEventArgs e)
{
//如果有时间空隙,加入空格
DateTime dtNow = DateTime.Now;
if (dtNow - dtLast > TimeSpan.FromMilliseconds(100))
stackOutput.Children.Add(new TextBlock(new Run()));
dtLast = dtNow;
//显示事件信息
TextBlock text = new TextBlock();
text.FontFamily = fontfam;
text.Text = string.Format(strformat, e.RoutedEvent.Name,
TypeWithoutNamespace(sender),
TypeWithoutNamespace(e.Source),
TypeWithoutNamespace(e.OriginalSource));
stackOutput.Children.Add(text);
(stackOutput.Parent as ScrollViewer).ScrollToBottom();
}
string TypeWithoutNamespace(object obj)
{
string[] str = obj.GetType().ToString().Split('.');
return str[str.Length-1];
}
}
}
2.自定义路由事件
(1)声明并注册路由事件
(2)为路由事件添加CLR事件包装
(3)创建可以激发路由事件的方法
以ButtonBase类中定义的Click路由事件为例:
public abstract class ButtonBase : ContentControl, ICommandSource
{
//字段 声明路由事件
public static readonly RoutedEvent ClickEvent;
//构造函数 在静态构造函数中注册路由事件,也可在直接申明字段同时注册路由事件
static ButtonBase()
{
//第1个参数为事件名
//第2个参数为路由策略,有三种策略:Bubble(冒泡式),Tunnel(隧道式),Direct(直达式)
//第3个参数为用于指定事件处理器的类型,该类型必须为委托类型,并且不能为 null
//第4个参数为路由事件所在的类名
ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));
}
//事件 将路由事件包装成CLR事件
public event RoutedEventHandler Click
{
add { base.AddHandler(ClickEvent, value); }
remove { base.RemoveHandler(ClickEvent, value); }
}
//方法 创建激发事件的方法
protected virtual void OnClick()
{
RoutedEventArgs e = new RoutedEventArgs(ClickEvent, this);
base.RaiseEvent(e);
}
}
进一步可参考:http://www.cnblogs.com/wilderhorse/articles/3231454.html
在进行上述自定义路由事件后,就可以像CLR事件一样,订阅事件和处理事件了。其中,订阅本身的事件同CLR事件一样,订阅子节点的事件用AddHandler方法,如上面“使用路由事件”中的例子。
《WPF程序设计指南》读书笔记——第9章 路由输入事件的更多相关文章
- css权威指南读书笔记-第10章浮动和定位
这一章看了之后真是豁然开朗,之前虽然写了圣杯布局和双飞翼布局,有些地方也是模糊的,现在打算总结之后再写一遍. 以下都是从<css权威指南>中摘抄的我认为很有用的说明. 浮动元素 一个元素浮 ...
- 《Javascript高级程序设计》读书笔记(1-3章)
第一章 JavaScript简介 1.1 JavaScript简史 略 1.2 JavaScript实现 虽然 JavaScript 和 ECMAScript 通常都被人们用来表达相同的含义,但 Ja ...
- JavaScript权威指南读书笔记【第一章】
第一章 JavaScript概述 前端三大技能: HTML: 描述网页内容 CSS: 描述网页样式 JavaScript: 描述网页行为 特点:动态.弱类型.适合面向对象和函数式编程的风格 语法源自J ...
- 《JavaScript高级程序设计》 - 读书笔记 - 第5章 引用类型
5.1 Object 类型 对象是引用类型的实例.引用类型是一种数据结构,用于将数据和功能组织在一起. 新对象是使用new操作符后跟一个构造函数来创建的.构造函数本身就是一个函数,只不过该函数是出于创 ...
- 《JavaScript高级程序设计》 - 读书笔记 - 第4章 变量、作用域和内存问题
4.1 基本类型和引用类型的值 JavaScript变量是松散类型的,它只是保存特定值的一个名字而已. ECMAScript变量包含两种数据类型的值:基本类型值和引用类型值.基本类型值指的是简单的数据 ...
- 《Linux程序设计》--读书笔记---第十三章进程间通信:管道
管道:进程可以通过它交换更有用的数据. 我们通常是把一个进程的输出通过管道连接到另一个进程的输入: 对shell命令来说,命令的连接是通过管道字符来完成的: cmd1 | cmd2 sh ...
- 《Visual C++ 程序设计》读书笔记 ----第8章 指针和引用
1.&取地址:*取内容. 2.指针变量“++”“--”,并不是指针变量的值加1或减1,而是使指针变量指向下一个或者上一个元素. 3.指针运算符*与&的优先级相同,左结合:++,--,* ...
- 《Linux内核设计与实现》第八周读书笔记——第四章 进程调度
<Linux内核设计与实现>第八周读书笔记——第四章 进程调度 第4章 进程调度35 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配 ...
- 《Linux内核设计与分析》第六周读书笔记——第三章
<Linux内核设计与实现>第六周读书笔记——第三章 20135301张忻估算学习时间:共2.5小时读书:2.0代码:0作业:0博客:0.5实际学习时间:共3.0小时读书:2.0代码:0作 ...
随机推荐
- css笔记16:盒子模型的入门案例
1.案例一: 效果图如下: (1)box1.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&quo ...
- 安装Laravel之坎坷记述
写这篇文章记录以及分享我安装Laravel框架的一些经验 过程如下: 1.按照官方的描述,第一步是先安装composer来管理依赖=>composer下载传送门 下载之后点击安装,按照提示它需要 ...
- 网络编程(发送get和post请求到服务器端,并获取响应)
一:B/S结构,浏览器端到服务器端通信依赖http协议 交互过程: 1:在浏览器地址栏输入http://ip:port/应用/资源路径 2:浏览器根据ip和服务器建立连接,port确定和那个应用进行交 ...
- hdu 4614 线段树
思路:当k为1的时候,用二分法查询包含有f个空瓶的上界r,然后更新会方便很多,直接更新区间(a,r)了. #include<iostream> #include<cstdio> ...
- C#使用HttpHelper万能框架,重启路由器
首先声明,不是所有路由器都可以通过下面的代码来让路由器执行重启. 下面的代码测试的路由器是(TP-LINK TD-W89841N增强型).要根据自己的路由器来写代码. using CsharpHttp ...
- css3 web字体记
css3 web字体 @font-face语法 @font-face能够加载服务器端的字体,让客户端浏览器显示客户端没有安装的字体. @font-face{ font-family:<YourW ...
- jquery之css()改变字体大小,颜色,背景色
转: <script type="text/javascript"> $(document).ready(function() { $("#f ...
- sqlserver关于事务
事务的四个特性: 原子性,一致性,持久性,隔离性 原子性: 原子性:表示事务执行是作为原子,不可分割,整个语句要么执行,要么不执行sqlserver中每一个单独的语句可以看做是包含在事务中每一句本身具 ...
- 在ASP.NET项目中使用CKEditor +CKFinder实现图片上传功能
前言 之前的项目中一直使用的是FCKeditor,昨天突然有个想法:为什么不试一下新的CKEditor呢?于是花了大半天的时间去学习它的用法,现在把我的学习过程与大家分享一下. 谈起FCKeditor ...
- MVC3、如何应用EntityFramework 连接MySql 数据库
原文:MVC3.如何应用EntityFramework 连接MySql 数据库 新的一年,新的开始. 今天总结的主题是在MySql中应用EntityFramework 的Code First模式. 开 ...