概述: 

WPF中的Canvas是常用的一个绘图控件,可以方便地在Canvas中添加我们需要处理的各种元素如:图片、文字等。但Canvas中元素增加到一定数量,并且有重合的时候,我们如何通过在Canvas中点击鼠标,获得我们想要的元素,然后再对该元素做出相应的控制?

命中测试,可以很好地解决这个问题

本文目的: 

使用命中测试,选取Canvas中相应Element。

正文: 

可视化树如何影响命中测试

可视化树中的起始点确定在对象的命中测试枚举过程中返回哪些对象。如果有多个要执行命中测试的对象,则可视化树中用作起始点的可视化对象必须是所有相关对象的公共上级。例如,如果您希望对以下关系图中的按钮元素和绘图可视化对象执行命中测试,则必须将可视化树中的起始点设置为两者的公共上级。在本例中,画布元素是按钮元素和绘图可视化对象的公共上级。

可视化树层次结构的关系图

即要在命中测试的结果中,包含Button及Drawing Visual,就必须在他们的公共上级Canvas中做命中测试。

示例

Canvas中放置了底层放置了一张图片,顶层放置了一个文本框,我们想实现点击文本框区域时,命中测试的返回结果为下层的Image,先贴上代码,然后再解释。

private void canvasMain_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
GetCurrentElement(e.GetPosition(canvasMain));
} private void GetCurrentElement(Point point)
{
PointHitTestParameters parameters = new PointHitTestParameters(point);
VisualTreeHelper.HitTest(canvasMain, HitTestFilter, HitTestCallback, parameters);
} private HitTestResultBehavior HitTestCallback(HitTestResult result)
{
Image image = result.VisualHit as Image;
if (image != null)
   {
_currentElement = image;
return HitTestResultBehavior.Stop;
} else
return HitTestResultBehavior.Continue;
} private HitTestFilterBehavior HitTestFilter(DependencyObject o)
{
Type type = o.GetType();
switch (type.Name)
{
case "Canvas":
return HitTestFilterBehavior.ContinueSkipSelf;
default:
return HitTestFilterBehavior.Continue;
}
}

其中VisualTreeHelper.HitTest方法是最主要的方法,其有三种重载形式,我们使用的是第二种重载形式,参数及其含义如下:

参数名称

类型

说明

reference

System.Windows.Media.Visual

要进行命中测试的 Visual

filterCallback

System.Windows.Media.HitTestFilterCallback

表示命中测试筛选回调值的方法

resultCallback

System.Windows.Media.HitTestResultCallback

表示命中测试结果回调值的方法

hitTestParameters

System.Windows.Media.HitTestParameters

要进行命中测试的参数值

1. reference

这个参数不用多说,就是我们要进行命中测试元素的公共上级,即他们在WPF树结构的上级,在这里为“canvasMain”;

2. filterCallback

使用命中测试筛选回调函数可以枚举呈现内容包含指定坐标的所有可视化对象。但是,您可能要忽略不希望在命中测试结果回调函数中处理的可视化树的某些分支。命中测试筛选回调函数的返回值确定可视化对象的枚举应执行的操作类型。例如,如果返回值 ContinueSkipSelfAndChildren,则可从命中测试结果枚举中移除当前可视化对象及其子对象。 这意味着命中测试结果回调函数在其枚举中将看不到这些对象。修剪可视化对象树会减少命中测试结果枚举过程中的处理量。其效果如下所示:

示例代码中我们并不想对Canvas进行命中测试,所以我们就判断如果枚举的命中测试结果为Canvas,则返回HitTestFilterBehavior.ContinueSkipSelf,这样将忽略它,而对其子对象进行命中测试。

下面是HitTestFilterBehavior的成员列表,我们可以根据需要,返回不用的值,以筛选命中测试结果。

成员名称

说明

ContinueSkipChildren

针对当前的 Visual(但不包括其子代)进行命中测试。

ContinueSkipSelfAndChildren

不要针对当前的 Visual 或其子代进行命中测试。

ContinueSkipSelf

不要针对当前的 Visual 进行命中测试,但要针对其子代进行命中测试。

Continue

针对当前的 Visual 及其子代进行命中测试。

Stop

在当前 Visual 处停止命中测试。

3. resultCallback

表示命中测试结果回调值的方法。result.VisualHit即为本次命中测试的结果,可以根据其类型判断其是否符合我们的测试要求,如果不符合则返回HitTestResultBehavior.Continue,继续枚举命中测试的下一个结果,如果符合要求则可以使用变量来接受这个结果,然后直接调用HitTestResultBehavior.Stop来结束整个命中测试。

4. hitTestParameters

定义命中测试的参数。从此公共基类派生出来的可用于实际命中测试的类包括 PointHitTestParameters 和 GeometryHitTestParameters。根据名称亦可以看出PointHitTestParameters主要用于点测试,而GeometryHitTestParameters则可以用于区域内的命中测试,该类型的详细信息请查询MSDN。

PointHitTestParameters的初始化也很简单,只需传入我们需要进行命中测试的点(Point)即可。

OK,主要的方法及其含义都解释完毕,想必大家都已能看明白示例代码,对命中测试也有了一个初步的了解。实际情况中可以根据情况,灵活运用filterCallback和resultCallback这两个回调函数,做到复杂的命中测试。

注意事项:

1. WPF大多控件都有IsHitTestVisible 属性,其可获取或设置一个值,该值声明某个 UIElement 派生对象是否可以作为其呈现内容某部分的命中测试结果返回。 这样,您便可以选择性地更改可视化树,以确定命中测试中涉及哪些可视化对象。

2. 在命中测试结果枚举过程中,不应执行修改可视化树的任何操作。在遍历可视化树的过程中,在可视化树中添加或移除对象会导致不可预知的行为。您可以在 HitTest 方法返回之后安全地修改可视化树。 您可能想要提供一个数据结构(例如 ArrayList),以便在命中测试结果枚举期间存储值。

3. 命中的可视化对象按 Z 顺序进行枚举。Z 顺序中位于最顶层的可视化对象最先进行枚举。所有其他可视化对象按递减的 Z 顺序级别进行枚举。此枚举顺序对应于可视化对象的呈现顺序。

(非原创)

WPFの命中测试的更多相关文章

  1. WPF命中测试示例(二)——几何区域命中测试

    原文:WPF命中测试示例(二)--几何区域命中测试 接续上次的命中测试,这次来做几何区域测试示例. 示例 首先新建一个WPF项目,在主界面中拖入一个按钮控件,并修改代码中的以下高亮位置: 当前设计视图 ...

  2. WPF命中测试示例(一)——坐标点命中测试

    原文:WPF命中测试示例(一)--坐标点命中测试 命中测试也可被称为碰撞测试,在WPF中使用VisualTreeHelper.HitTest()方法实现,该方法用于获取给定的一个坐标点或几何形状内存在 ...

  3. wpf datagrid row的命中测试

    1. 添加鼠标左键处理 AddHandler(DataGrid.MouseLeftButtonDownEvent, new RoutedEventHandler(grdStudyList_MouseL ...

  4. WPF技巧:命中测试在视觉树中的使用

    我们有时候又需求从当前视觉树中找一些东西,比如鼠标按下的时候,看看鼠标下的元素都有什么.又比如某块区域下有哪些元素?某个坐标点下有哪些元素? 这些需求在使用 命中测试的时候,可以非常方便和快速的去找到 ...

  5. 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

    原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...

  6. 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性

    [源码下载] 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性 作者:w ...

  7. WPF 触摸到事件

    原文:WPF 触摸到事件 本文从代码底层告诉大家,在触摸屏幕之后是如何拿到触摸点并且转换为事件 在 WPF 界面框架核心就是交互和渲染,触摸是交互的一部分.在 WPF 是需要使用多个线程来做触摸和渲染 ...

  8. WPF 使用WindowChrome自定义窗体 保留原生窗体特性

    本文大幅度借鉴dino.c大佬的文章 https://www.cnblogs.com/dino623/p/uielements_of_window.html https://www.cnblogs.c ...

  9. 2019-6-15-WPF-触摸到事件

    原文:2019-6-15-WPF-触摸到事件 title author date CreateTime categories WPF 触摸到事件 lindexi 2019-06-15 08:58:54 ...

随机推荐

  1. Solr04 - 在Jetty和Tomcat上部署Solr单机服务

    目录 1 准备安装环境 2 通过内部Jetty服务器启动 3 通过配置Tomcat服务器启动 3.1 删除不需要的应用 3.2 修改服务端口 3.3 部署solr.war 3.4 扩展: 虚拟目录发布 ...

  2. Chapter 5 Blood Type——11

    "I just wondered… if you could warn me beforehand the next time you decide to ignore me for my ...

  3. Kafka控制器选举流程剖析

    1.概述 平时在使用Kafka的时候,可能关注的更多的是Kafka系统层面的.今天来给大家剖析一下Kafka的控制器,了解一下Kafka控制器的选举流程. 2.内容 Kafka控制器,其实就是一个Ka ...

  4. 实战Kafka ACL机制

    1.概述 在Kafka0.9版本之前,Kafka集群时没有安全机制的.Kafka Client应用可以通过连接Zookeeper地址,例如zk1:2181:zk2:2181,zk3:2181等.来获取 ...

  5. RabbitMQ消息队列(五)-安装amqp扩展并订阅/发布Demo(.Net Core版)

    publish发布消息 新建一个Asp.Net Core控制台项目:PublishDemo 安装Nuget包 Install-Package RabbitMQ.Client 添加命名空间引用 usin ...

  6. angr进阶(4)从任意位置开始

    从程序的任意位置开始可以大大的减少测试的时间,使用的方法是控制程序运行到某时刻的寄存器的值来进行的.asisctffinals2015_fake p = angr.Project("fake ...

  7. MySQL 索引及查询优化总结

    本文由云+社区发表 文章<MySQL查询分析>讲述了使用MySQL慢查询和explain命令来定位mysql性能瓶颈的方法,定位出性能瓶颈的sql语句后,则需要对低效的sql语句进行优化. ...

  8. JDBC设计理念浅析 JDBC简介(一)

    概念 JDBC是J2EE的标准规范之一,J2EE就是为了规范JAVA解决企业级应用开发制定的一系列规范,JDBC也不例外. JDBC是用于Java编程语言和数据库之间的数据库无关连接的标准Java A ...

  9. Leetcode 第133场周赛解题报告

    今天参加了leetcode的周赛,算法比赛,要求速度比较快.有思路就立马启动,不会纠结是否有更好的方法或代码可读性.只要在算法复杂度数量级内,基本上是怎么实现快速就怎么来了. 比赛时先看的第二题,一看 ...

  10. 【Angular专题】——(1)Angular,孤傲的变革者

    目录 一. 漫谈Angular 二. 如果你还在使用Angularjs 三. 我计划这样学习Angular技术栈 一. 漫谈Angular Angular,来自Google的前端SPA框架,与Reac ...