迟到的 WPF 学习 —— 路由事件
1. 理解路由事件:WPF 通过事件路由(event routing)概念增强了传统的事件执行的能力和范围,允许源自某个元素的事件由另一个元素引发,例如,事件路由允许工具栏上的一个按钮点击的事件在被代码处理之前上传到工具栏,再由工具栏上传到所属窗体
2. 定义、注册和包装路由事件:和依赖性属性类似,它由只读的静态字段表示,在一个静态构造函数中注册,并通过一个标准的 .Net 事件定义进行包装。如 Button 的 Click 事件,该事件继承自抽象的 ButtonBase 基类
public abstract class ButtonBase:ContentControl...
{
//The event definition
public static readonly RoutedEvent ClickEvent; // event registration
static ButtonBase()
{
ButtonBase.ClickEvent = EventManager.RegisterRoutedEvent(
"Click",RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(ButtonBase));
...
} // The traditional event wrapper
public event RoutedEventHandler Click
{
add{
base.AddHandler(ButtonBase.ClickEvent,value);
}
remove{
base.RemoveHandler(ButtonBase.ClickEvent,value);
}
}
}
通过使用普通的事件定义进行包装,确保所有 .Net 的语言都能访问它。AddHandler 和 RemoveHandler 是在 FrameworkElement 中定义的,并被每个 WPF 元素继承。
3. 处理路由事件:从语法上,XAML 可以这样写
<Image Source="happy.jpg" Stretch="None" Name="img" MouseUp="img_MouseUp"/>
比较约定俗成的命名方式是“元素名_事件名”,如没有交互的极简事件也可以不命名元素
<Button Click="cmdOk_Click">OK</Button>
C# 还允许流线型的写法,隐式创建合适的委托对象
img.MouseUp += img_MouseUp;
上面的代码依赖事件包装器,事件包装器调用的是 UIElement.AddHandler() 方法,也可以直接调用直连事件
img.AddHandler(Image.MouseUpEvent,new MouseButtonEventHandler(img_MouseUp));
也可以使用“定义事件的类的名称”而不是用“引用事件的类的名称”,如改造成下面的写法
img.AddHandler(UIElement.MouseUpEvent,new MouseButtonEventHandler(img_MouseUp));
两种写法在语法上是等效的,但第二种的缺点是,不能明确的指明 MouseUpEvent 是由 Image 提供的,在嵌套的元素中,可能会引起混论和遗忘,是代码难于理解。
想要断开事件,只能使用代码
img.MouseUp -= img_MouseUp;
或 UIElement.RemoveHandler() 方法
img.RemoveHandler(Image.MouseUpEvent,new MouseButtonEventHandler(img_MouseUp));
为同一事件多次连接相同的事件处理程序,在技术上是可行的,但属于编码错误,事件处理程序会被触发多次,即 += 就多加一次,-= 也只减一次
4. 事件路由:模拟一个场景,一个 Label 包含一个 StackPanel 面板,面板中包含两个 TextBlock 和一个 Image。现在,想要点击 Label 中的任意元素都触发同一个事件处理程序。当然可以为每一个元素的 MouseUp 和 MouseDown 都关联到相同的事件处理程序,但这将使代码看起来混乱不好维护,WPF 使用事件路由模型提供了更好的方法。
路由事件有三种方式实现:
直接路由事件(Direct event),起源于一个元素,不传递其它元素。
在包含的层次中向上传递的冒泡路由事件(Bubbling event),例如 MouseDown 就是一个泡泡事件,首先由改元素引发、再由父元素引发、最后被父元素的父元素引发,直至 WPF 元素树顶部。
在包含的层次中向下传递的隧道路由事件(Tunneling event),隧道事件在到达恰当的控件前为预览事件(或可能终止的事件)创造了机会,例如,PreviewKeyDown 可以截获是否按下了一个键,首先在窗口级别上,然后是容器,直到到达按下键时具有焦点的元素。
使用 EventManger.RegisterEvent 注册事件时,传递 RoutingStrategy 枚举值指示希望应用于事件的行为
5. 处理挂起的事件:当事件的 Handle 属性被置为 true 意味着通知其它侦听对象此事件被处理过了,有一个方法用于接收被处理过的事件,它必须使用前面介绍过的 AddHandler 方法的一个重载版本,将第三个 bool 类型参数设置为 true(举以下代码这个例子不太恰当,会有隐患,在此遵照原内容)
cmdClecr.AddHandler(UIElement.MouseUpEvent,new MouseButtonEventHandler(cmdClear_MouseUp),true)
6. 附加事件:如果一个 StackPanel 里边有数个 Button 并且希望这些 Button 在点击时都能处理相同的事件,通常的想法是将所有 Button 的 Click 事件都关联到相同的处理程序,但在 WPF 中,可以通过在更高层次的元素上处理这个事件来解决,如下面
<StackPanel Click="DoSomething">
<Button Name="cmd1">Command 1</Button>
<Button Name="cmd2">Command 2</Button>
<Button Name="cmd3">Command 3</Button>
</StackPanel>
看起来写的很美,但实际不能运行,因为 StackPanel 木有 Click 事件,咋办?可以这样
<StackPanel Button.Click="DoSomething"/>
以“类名.事件名”的方式使用不同的关联事件的语法,解释一下,Click 是在 ButtonBase 中定义的,Button 继承自 ButtonBase。如果使用 ButtonBase.Click 的方式那么所有继承自 ButtonBase 的控件在单击时,都将使用“DoSomething”事件处理程序,Button.Click 更加精确。可以在代码中关联附加事件,但必须要用 AddHandler 而不是 +=,如(StackPanel 被命名为 pnlButtons)
pnlButtons.AddHandler(Button.Click,new RoutedEventHandler(DoSomething));
这会碰到一个问题,DoSomething 方法中如果想知道具体是谁引发了事件怎么办?可以依靠判断 sender 比如 sender == cmd1,但这需要为每个 Button 都设置 Name 属性,另一个选择是随按钮传递一个可在代码中使用的信息,比如为每个 Button 设置一个 Tag 属性
<StackPanel Click="DoSomething">
<Button Name="cmd1" Tag=“The first button”>Command 1</Button>
<Button Name="cmd2" Tag=“The second button”>Command 2</Button>
<Button Name="cmd3" Tag=“The third button”>Command 3</Button>
</StackPanel>
然后在 DoSomething 中这样
private void DoSomething(object sender,RoutedEventArgs e )
{
object tag = ((FrameworkElement)sender).Tag;
MessageBox.Show((string)tag);
}
7. 隧道路由:和冒泡类型,方向相反,在一个控件中引发的事件最先从顶层(通常是窗体)开始引发,然后是容器,最后到达实际引发的控件。隧道事件容易识别,它们都是以 Preview 开头,WPF 通常成对的定义冒泡和隧道,且隧道路由事件总是在冒泡路由事件前被引发。注意,如果隧道事件被标记为已处理,那么冒泡将不会被引发,这是因为两者共享一个 RoutedEventArg 对象的实例。
点击下载代码 —— 需 .Net Framework 4 或以上
迟到的 WPF 学习 —— 路由事件的更多相关文章
- WPF - 善用路由事件
原文:WPF - 善用路由事件 在原来的公司中,编写自定义控件是常常遇到的任务.但这些控件常常拥有一个不怎么好的特点:无论是内部还是外部都没有使用路由事件.那我们应该怎样宰自定义控件开发中使用路由事件 ...
- 学习WPF——了解路由事件
入门 我们先来看一个例子 前台代码: 后台代码: 点击按钮的运行效果第一个弹出窗口 第二个弹出窗口: 第三个弹出窗口: 说明 当点击按钮之后,先触发按钮的click事件,再上查找,发现stackpan ...
- WPF的路由事件、冒泡事件、隧道事件(预览事件)
本文摘要: 1:什么是路由事件: 2:中断事件路由: 3:自定义路由事件: 4:为什么需要自定义路由事件: 5:什么是冒泡事件和预览事件(隧道事件): 1:什么是路由事件 WPF中的事件为路由事件,所 ...
- WPF:自定义路由事件的实现
路由事件通过EventManager,RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数:通过RaiseEvent方法来 ...
- 【WPF】路由事件
总结WPF中的路由事件,我将学到的内容分为四部分来逐渐掌握 第一部分:wpf中内置的路由事件 以Button的Click事件来说明内置路由事件的使用 XAML代码: <Window x:Clas ...
- WPF自定义路由事件(二)
WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件. 1.WPF内置路由事件 WPF ...
- WPF中路由事件的传播
路由事件(RoutedEvent)是WPF中新增的事件,使用起来与传统的事件差别不大, 但传播方式是完全不同的. 路由事件的传播方式 通过RoutingStrategy来定义传播的方式 public ...
- WPF 冒泡路由事件
在WPF中,例如,可以构建一个包含图形的按钮,创建一个具有文本和图片混合内容的标签,或者为了实现滚动或折叠的显示效果在一个特定的容器中放置内容.甚至可以多此重复嵌套,直到达到您所希望的层次深度. 这种 ...
- WPF 隧道路由事件
阅读本文前,请先了解 冒泡路由事件:http://www.cnblogs.com/andrew-blog/p/WPF_BubbledEvent.html 隧道路由事件的工作方式和冒泡路由事件相同,但方 ...
随机推荐
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(4)-业务逻辑层的封装
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(4)-业务逻辑层的封装 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 (2) ...
- 细说 ASP.NET Cache 及其高级用法【转】
阅读目录 开始 Cache的基本用途 Cache的定义 Cache常见用法 Cache类的特点 缓存项的过期时间 缓存项的依赖关系 - 依赖其它缓存项 缓存项的依赖关系 - 文件依赖 缓存项的移除优先 ...
- Android游戏开发研究与主角在地图滚动
让人感动的地图过程平滑滚动 玩过rpg朋友应该都知道RPG的游戏地图一般都比較大 今天我和大家分享一下在RPG游戏中怎样来处理超出手机屏幕大小的游戏地图. 如图所看到的为程序效果 ...
- Cocos2d-android游戏引擎-介绍
一.游戏引擎概念 什么是游戏引擎 游戏引擎是指一些已编写好的可编辑游戏系统或者一些交互式实时图像应用程序的核心组件.这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在于让游戏设计 ...
- WebService对跨域的支持
WebService对跨域的支持 跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源, ...
- 基于Cocos2dx + box2d 愤怒的小鸟的实现Demo
1. Demo初始界面 2. 游戏界面 3. 精确碰撞检測 4. 下载 压缩文件文件夹 AngryBird source 愤慨的小鸟Demo源码,基于Cocos2dx C++,以及box2d技 ...
- c# 文件同步服务器,iis 集群 ,代码同步(二)
打算自己做一个 集群 代码同步软件. 基于Socket 和 FileSystemWatcher .
- linux cat
cut是一个选取命令,就是将一段数据经过分析,取出我们想要的.一般来说,选取信息通常是针对“行”来进行分析的,并不是整篇信息分析的. (1)其语法格式为:cut [-bn] [file] 或 cut ...
- Introducing Visual Studio’s Emulator for Android
visual studio 2015支持Android开发了. Microsoft released Visual Studio 2015 Preview this week and with it ...
- 分布式基础学习(2)分布式计算系统(Map/Reduce)
二. 分布式计算(Map/Reduce) 分 布式式计算,同样是一个宽泛的概念,在这里,它狭义的指代,按Google Map/Reduce框架所设计的分布式框架.在Hadoop中,分布式文件 系统,很 ...