WPF技巧:命中测试在视觉树中的使用
我们有时候又需求从当前视觉树中找一些东西,比如鼠标按下的时候,看看鼠标下的元素都有什么。又比如某块区域下有哪些元素?某个坐标点下有哪些元素?
这些需求在使用 命中测试的时候,可以非常方便和快速的去找到我们需要的内容。
简单命中测试
我们写一个最简单的命中测试的示例,来了解命中测试。我在一个画板上在不同的位置放了3个圆形。给他们放置了不同的位置和填充不同的颜色,我们通过命中测试判断如果鼠标在圆上抬起了,我们读取当前圆的填充颜色。
<Window x:Class="WPFVisualTreeHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFVisualTreeHelper"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid MouseLeftButtonUp="Grid_MouseLeftButtonUp">
<Canvas>
<Ellipse Canvas.Left="30" Canvas.Top="200" Width="130" Height="130" Fill="Blue"/>
<Ellipse Canvas.Left="110" Canvas.Top="0" Width="130" Height="130" Fill="Red"/>
<Ellipse Canvas.Left="220" Canvas.Top="100" Width="130" Height="130" Fill="Yellow"/>
<TextBlock Canvas.Left="0" Canvas.Top="0" Text="抬起鼠标左键,开始对鼠标所在点进行命中测试" />
</Canvas>
</Grid>
</Window>
我们给Grid 添加了左键抬起的事件。
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes; namespace WPFVisualTreeHelper
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var ellipse = GetVisual(e.GetPosition(this));
;
MessageBox.Show(ellipse?.Fill?.ToString());
} private Ellipse GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
var ellipse = hitResult.VisualHit as Ellipse;
return ellipse;
}
}
}
如果在圆上抬起,我们会显示圆的填充色。

我们简单命中测试使用VisualTreeHelper来进行命中测试。HitTest方法传入2个参数,一个参数在什么元素上查找,第二个参数是坐标。返回的对象是命中测试的返回结果,是DependencyObject类型的对象。我们的ui元素都是继承自DependencyObject的。找到的结果是HitTestResult,需要我们自己转换VisualHit到我们需要的类型,我们的方法如果不是该类型就返回为空。因为是简单命中测试。后面会封装一个命中测试的方法。因为在命中测试过程中,会有元素的层级关系,多个同类型元素集合,等等的需求。所以这里只了解什么是命中测试。能看懂代码就可以了,理解什么是命中测试。就可以了。
复杂命中测试
我们通过在VisualTreeHelper的HitTest上F12我们可以看到有3个方法的重载。

VisualTreeHelper类使用其他重载版本可以执行更复杂的命中测试。我们可以检索位于特定点的所有可视化对象,也可以使用特定区域的所有可视化对象。我们使用第一个重载方法。
因为在视觉树下,有层级和同级多个元素的问题。为了使用这个功能,我们需要创建回调函数,也就是第一个HitTest的第三个参数resultCallback。我们通过自上而下遍历所有可视对象,如果发现了匹配的对象就使用回调函数传递相关的内容直到找到所有的对象。

我们写个例子,我们在上面的例子上多添加几个圆形,并且把他们叠加起来,然后我们创建一个10*10像素的形状,去检索这个形状坐标下的所有圆形。为了让他们显示层叠关系我设置了opacity属性。并使用鼠标右键来执行复杂命中测试。 <Window x:Class="WPFVisualTreeHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFVisualTreeHelper"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid MouseLeftButtonUp="Grid_MouseLeftButtonUp" MouseRightButtonUp="Grid_MouseRightButtonUp">
<Canvas>
<Ellipse Canvas.Left="30" Canvas.Top="200" Width="130" Height="130" Fill="Blue"/>
<Ellipse Opacity="0.6" Canvas.Left="70" Canvas.Top="50" Width="130" Height="130" Fill="Violet"/>
<Ellipse Opacity="0.6" Canvas.Left="150" Canvas.Top="50" Width="130" Height="130" Fill="Orange"/>
<Ellipse Opacity="0.6" Canvas.Left="110" Canvas.Top="0" Width="130" Height="130" Fill="Red"/>
<Ellipse Canvas.Left="220" Canvas.Top="100" Width="130" Height="130" Fill="Yellow"/>
<TextBlock Canvas.Left="0" Canvas.Top="0" Text="抬起鼠标左键,开始对鼠标所在点进行命中测试" />
</Canvas>
</Grid>
</Window>
后台代码:
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes; namespace WPFVisualTreeHelper
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DrawingVisual v = new DrawingVisual(); }
#region 简单命中测试
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var ellipse = GetVisual(e.GetPosition(this));
;
MessageBox.Show(ellipse?.Fill?.ToString());
}
private Ellipse GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
var ellipse = hitResult.VisualHit as Ellipse;
return ellipse;
}
#endregion #region 复杂命中测试
private void Grid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
Point pt = e.GetPosition((UIElement)sender);
//我们定义一个10*10大小的几何
EllipseGeometry expandedHitTestArea = new EllipseGeometry(pt, 10.0, 10.0);
var ellipses = GetVisual(expandedHitTestArea);
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in ellipses)
{
stringBuilder.Append(item.Fill.ToString() + ",");
}
MessageBox.Show(stringBuilder.ToString());
} private HitTestResultBehavior HitTestCallback(HitTestResult result)
{
GeometryHitTestResult geometryResult = (GeometryHitTestResult)result;
Ellipse visual = result.VisualHit as Ellipse;
if (visual != null)
{
hits.Add(visual);
}
return HitTestResultBehavior.Continue;
}
List<Ellipse> hits = new List<Ellipse>();
private List<Ellipse> GetVisual(Geometry region)
{
hits.Clear();
GeometryHitTestParameters parameters = new GeometryHitTestParameters(region);
HitTestResultCallback callback = new HitTestResultCallback(this.HitTestCallback);
//第一个参数是我们要在什么容器内查找(我们现在是在整个window),第二个参数是筛选回调值的方法,我们目前不需要,
//第三个参数是命中测试回调结果。第四个参数是需要检测的区域。
VisualTreeHelper.HitTest(this, null, callback, parameters);
return hits;
}
#endregion }
}
HitTestCallback就是我们基于搜索结果回调的关键方法。我们查找了这个几何图形下的所有ellispe。
命中测试的封装
这里搞错了,这里封装的是查找元素的封装。。这个在补完C#的知识文章后更改。
我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085
WPF技巧:命中测试在视觉树中的使用的更多相关文章
- WPF命中测试示例(一)——坐标点命中测试
原文:WPF命中测试示例(一)--坐标点命中测试 命中测试也可被称为碰撞测试,在WPF中使用VisualTreeHelper.HitTest()方法实现,该方法用于获取给定的一个坐标点或几何形状内存在 ...
- WPFの命中测试
概述: WPF中的Canvas是常用的一个绘图控件,可以方便地在Canvas中添加我们需要处理的各种元素如:图片.文字等.但Canvas中元素增加到一定数量,并且有重合的时候,我们如何通过在Canv ...
- WPF命中测试示例(二)——几何区域命中测试
原文:WPF命中测试示例(二)--几何区域命中测试 接续上次的命中测试,这次来做几何区域测试示例. 示例 首先新建一个WPF项目,在主界面中拖入一个按钮控件,并修改代码中的以下高亮位置: 当前设计视图 ...
- wpf datagrid row的命中测试
1. 添加鼠标左键处理 AddHandler(DataGrid.MouseLeftButtonDownEvent, new RoutedEventHandler(grdStudyList_MouseL ...
- 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试
原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...
- 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性
[源码下载] 背水一战 Windows 10 (69) - 控件(控件基类): UIElement - Manipulate 手势处理, 路由事件的注册, 路由事件的冒泡, 命中测试的可见性 作者:w ...
- 分页技巧_测试并继续改进分页用的QueryHelper辅助对象
分页技巧_测试并继续改进分页用的QueryHelper辅助对象 QueryHelper.java /** * 用于辅助拼接HQL语句 */ public class QueryHelper { pri ...
- WPF技巧-Canvas转为位图
转自:http://www.cnblogs.com/tmywu/archive/2010/09/14/1825650.html 在WPF中我们可以将Canvas当成一种画布,将Canvas中的控件当成 ...
- WPF 一个数据库连接测试的实现
要实现的功能效果图如下:因为我们要测试数据是从输入框获得的,所以,我们的连接字符串不是写死在应用程序中的.下面我就详细介绍一下.
随机推荐
- mysql事务实现方式
事务是由一组SQL语句组成的逻辑处理单元,事务具有4属性,通常称为事务的ACID属性. 原子性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行. 由und ...
- 微信小程序在ios系统不兼容new Date('yyyy-mm-dd')
微信小程序中使用new Date('2021-04-01 10:11:20')来转换时间在苹果手机不生效 兼容写法为new Date('2021/04/01 10:11:20')
- 【odoo14】【用户侧】权限配置
以下内容仅适用于odoo的客户,不适用于开发人员. 下文介绍中涉及的概念及UI均是在odoo14社区版中进行. 目录 一. odoo中的对象 二. 权限控制 2.1 实现原理 2.2 UI方式实现权限 ...
- 4D雷达成像技术
4D雷达成像技术 当我们谈及3D捕捉时,总是先想到光学传感器.当我们讨论在第四维度(时间)讨论视觉数据时,倾向于考虑场景数据调度.这些是我们多年来关注激光雷达(LiDAR)和摄影测量,以及用户针对缓慢 ...
- Yolo:实时目标检测实战(上)
Yolo:实时目标检测实战(上) YOLO:Real-Time Object Detection 你只看一次(YOLO)是一个最先进的实时物体检测系统.在帕斯卡泰坦X上,它以每秒30帧的速度处理图像, ...
- JDBC连接MongoDB
pom文件中导入驱动 <!-- MongoDB驱动 --> <dependency> <groupId>org.mongodb</groupId> &l ...
- NX二次开发-将3X3矩阵修正为正交且长度为单位长度的矩阵
函数:UF_MTX3_ortho_normalize() 函数说明:将矩阵修正为正交且xyz长度为单位长度的矩阵.下图中输入的矩阵为三条线段的端点,经过修正后,生成一个坐标系. 1 #include ...
- 【VBA】列号与字母(列名)的相互转换 (自定义函数)
1. '列号转字母(列名) Function Num2Name(ByVal ColumnNum As Long) As String On Error Resume Next Num2Name = & ...
- Mysql慢SQL分析及优化
为何对慢SQL进行治理 从数据库角度看:每个SQL执行都需要消耗一定I/O资源,SQL执行的快慢,决定资源被占用时间的长短.假设总资源是100,有一条慢SQL占用了30的资源共计1分钟.那么在这1分钟 ...
- 【题解】Luogu P3110 [USACO14DEC]驮运Piggy Back
[题解]Luogu P3110 [USACO14DEC]驮运Piggy Back 题目描述 Bessie and her sister Elsie graze in different fields ...