原文:WPF RoutedEvent and HitTest - 简书

学习的时候切忌心浮气躁,慢慢的过每一个知识点,不要漏掉任何细节。不然当遇到细节问题的时候,会恼,会闹,会悔不该当初——花一下午调bug最后只改了一个参数有感。

相信很多用过WPF的人都知道WPF中的路由事件。一般看书的话,这个知识点也会在前几章讲到。总的来说,也就是

  • WPF的控件都存在于一颗Visual tree当中。
  • 事件在控件中的传递,其实也就是事件在Visual tree中的传递
  • 隧道事件从上往下,由树根开始向叶子传播
  • 冒泡事件从下往上,由子节点开始向根传播

假设我们有一个Visual tree长这样:

MainWindow
|_Border
|_Grid
|_TextBlock

那么如果用户点击了TextBlock。那么会产生什么事件,然后会怎么传递呢?

答案是

  1. 会产生PreviewMouseDown和MouseDown事件
  2. PreviewMouseDown是隧道事件,事件的顺序是MainWindow->Border->Grid->TextBlock
  3. MouseDown是冒泡事件,事件的顺序与之前相反,是TextBlock->Grid->Border->MainWindow

Tips:

如何查看WPF中的事件?有一个开源工具snoop可以帮助你。下图是一个实际示例,UI结构以及操作和上述一致。

example

好,我们再看一个例子。

MainWindow
|_Border
|_Grid
|_TextBlock(Margin="32")

和上个例子不同的地方在于,我们把TextBlock的边距扩大了。这就意味着,我们可以点击在TextBlock的边距上,那么会发生什么呢?先自己想想哦。

正确答案

注意这里的border是window中自带的,不是我们自己声明的。所以正确答案是,只传播到了MainWindow。为了区别,我给声明的Border随便起了个名字。

要是答对了的同学,那不是一般的棒!

我们这里有两个问题:

  1. PreviewMouseDown只传递到了MainWindow。作为一个隧道事件,没有继续往下传递。
  2. 触发事件的是MainWindow,不是Border也不是Grid。

先解答第一个问题。路由事件的准确触发顺序应该是

  1. 隧道事件从根开始,传播到产生事件的控件为止。如果中间有控件处理(e.Handled = true)掉,就停止传播。
  2. 冒泡事件从产生事件的控件开始,传播到根节点为止。如果中间有控件处理(e.Handled = true)掉,就停止传播。
  3. 系统提供的Preview事件先触发。如果被处理(e.Handled = true)掉,不会在产生对应的冒泡事件。

第二个问题就很恼人了。总的来说就是

  • 如果没有控件没有被渲染,那么该控件不能被HitTest,也不能被路由事件触发。(参见这里)

    也就是说,Border和Grid没能触发,是因为他们没有Background,没有被渲染。如果加上,即使你加的是TransParent,也会有效。

    添加了TransParent为Border的背景
    添加了TransParent为Grid的背景

也就是说,如果你希望下面的控件能够触发事件。那么让上面的控件不能被HitTest就可以了。我今天遇到的坑是,上面一层自己画的一个框,用的函数是

dc.DrawGeometry(Brushes.Transparent, new Pen(brush, GraphicsLineWidth), PathGeometry);

改成

dc.DrawGeometry(null, new Pen(brush, GraphicsLineWidth), PathGeometry);

就好了。

WPF RoutedEvent and HitTest - 简书的更多相关文章

  1. WPF ControllTemplate Triggers小记 - 简书

    原文:WPF ControllTemplate Triggers小记 - 简书 WPF中,样式模板中如果定义EventTrigger事件方式实现动画.那么需要注意两点: 1.对于绑定的属性的Event ...

  2. WPF 任务栏颜色 - 简书

    原文:WPF 任务栏颜色 - 简书 先看看效果,这种效果可以用来做进度条或者消息通知闪烁.   image.png   image.png   image.png   image.png 有一个好消息 ...

  3. WPF之路-键盘与鼠标事件 - 简书

    原文:WPF之路-键盘与鼠标事件 - 简书 键盘事件 事件类型分为以下几个类型 生命周期事件:在元素加载与卸载的时候发生 鼠标事件:鼠标动作 键盘事件:键盘动作 手写笔事件:适用于win7以上的系统 ...

  4. WPF 动画:同为控件不同命 - 简书

    原文:WPF 动画:同为控件不同命 - 简书 1. 及格与优秀 读大学的时候,有一门课的作业是用 PPT 展示. 但是我们很多同学都把 PPT 当做 Word 来用,就单纯地往里面堆文字. 大家都单纯 ...

  5. WPF使用IDataErrorInfo接口进行数据校验 - 简书

    原文:WPF使用IDataErrorInfo接口进行数据校验 - 简书 class ValidationBindableBase : BindableBase, IDataErrorInfo { pu ...

  6. c#字符串加载wpf控件模板代码 - 简书

    原文:c#字符串加载wpf控件模板代码 - 简书 ResourceManager resManagerA = new ResourceManager("cn.qssq666.Properti ...

  7. WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书

    原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是 ...

  8. WPF系列教程——(三)使用Win10 Edge浏览器内核 - 简书

    原文:WPF系列教程--(三)使用Win10 Edge浏览器内核 - 简书 在需要显示一些 H5网站的时候自带的WebBrowser总是显示不了,WebBrowser使用的是IE内核,许多H5新特性都 ...

  9. WPF系列教程——(一)仿TIM QQ界面 - 简书

    原文:WPF系列教程--(一)仿TIM QQ界面 - 简书 TIM QQ 我们先来看一下TIM QQ长什么样,整体可以将界面分为三个部分 TIM QQ 1. 准备 阅读本文假设你已经有XAML布局的基 ...

随机推荐

  1. Angular组件之间通讯

    组件之间会有下列3种关系: 1. 父子关系 2. 兄弟关系 3. 没有直接关系 通常采用下列方式处理(某些方式是框架特有)组件间的通讯,如下: 1父子组件之间的交互(@Input/@Output/模板 ...

  2. cocos2d::CCFileUtils::sharedFileUtils()->getFileData(szFile, "r", &bufferSize) 不同平台返回值不一样

    string pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName); unsigned char* pB ...

  3. Django中模型(四)

    Django中模型(四) 五.创建对象 1.目的 向数据库中添加数据.当创建对象时,Django不会对数据库进行读写操作,当调用save()方法时,才与数据库交互,将对象保存到数据库中 2.注意 __ ...

  4. 随手练——HDU 1284 动态规划入门

    #include <iostream> #include <algorithm> #include <string.h> using namespace std; ...

  5. HDU - 5547 数独(回溯法)

    题目链接:HDU-5547 http://acm.hdu.edu.cn/showproblem.php?pid=5547 正所谓:骗分过样例,暴力出奇迹. 解题思想(暴力出奇迹(DFS+回溯)): 1 ...

  6. Kali-linux Arpspoof工具

    Arpspoof是一个非常好的ARP欺骗的源代码程序.它的运行不会影响整个网络的通信,该工具通过替换传输中的数据从而达到对目标的欺骗.本节将介绍Arpspoof工具的 使用. 9.8.1 URL流量操 ...

  7. svn .externals 属性

    问:如下自定下载关联模块呢? 答:第一步: 编辑svn.externals文本,如下所示 dir/moduel_name URL/module dir/moduel_name URL/module 第 ...

  8. 生产者-消费者模型-线程安全队列Queue

    #python3 #product new data into the queue #comsume data from the queue from queue import Queue impor ...

  9. Linux 嵌入式 开发环境 交叉编译安装

    1.安装 Ubuntu 系统 安装完毕,系统 提示 重启,这个时候 请拔掉U盘,进行重启 OK. 2.安装 NFS 服务 3.安装 openssh服务 4.开启openSSH服务 5.就可以使用 Wi ...

  10. php版本低更换php版本-问题以解决

    Parse error: syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or variable ...