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 一个数据库连接测试的实现
要实现的功能效果图如下:因为我们要测试数据是从输入框获得的,所以,我们的连接字符串不是写死在应用程序中的.下面我就详细介绍一下.
随机推荐
- DDD划分领域、子域,核心域,支撑域的目的
名词解释 在DDD兴起的原因以及与微服务的关系中曾举了一个研究桃树的例子,如果要研究桃树,将桃树根据器官分成根.茎.叶.花.果实.种子,这每一种器官都可以认为是一个研究领域,而领域又有更加具体的细分, ...
- node.js学习(7)流和管道
1 导入模块 输入流 # 读取流 # 写入流 # # 管道 # 压缩 # 解压缩
- 『动善时』JMeter基础 — 37、将JMeter测试结果写入Excel
目录 1.环境准备 (1)引入操作Excel文件的基础JAR包 (2)引入封装自定义操作Excel文件的JAR包 2.准备测试需要的数据 3.测试结果写入Excel演示 (1)测试计划内包含的元件 ( ...
- 硬件delay评估表
硬件delay评估表 硬件延时评估表用于快速评估一个模型在特定硬件环境和推理引擎上的推理速度. Bw 主要用于定义PaddleSlim支持的硬件延时评估表的格式. 概述 硬件延时评估表中存放着所有可能 ...
- MinkowskiEngine多GPU训练
MinkowskiEngine多GPU训练 目前,MinkowskiEngine通过数据并行化支持Multi-GPU训练.在数据并行化中,有一组微型批处理,这些微型批处理将被送到到网络的一组副本中. ...
- TorchScript神经网络集成技术
TorchScript神经网络集成技术 create_torchscript_neuropod 将TorchScript模型打包为neuropod包. create_torchscript_neuro ...
- 将HLSL射线追踪到Vulkan
将HLSL射线追踪到Vulkan Bringing HLSL Ray Tracing to Vulkan Vulkan标志 DirectX光线跟踪(DXR)允许您使用光线跟踪而不是传统的光栅化方法渲染 ...
- SpringBoot数据访问(一) SpringBoot整合Mybatis
前言 SpringData是Spring提供的一个用于简化数据库访问.支持云服务的开源框架.它是一个伞形项目,包含了大量关系型数据库及非关系型数据库的数据访问解决方案,其设计目的是为了使我们可以快速且 ...
- 【VBS】获取文件夹大小
文件截图: 运行结果: 第一步:编写脚本 GetFloderSize.vbs 1 '获得文件夹的大小 by 王牌飞行员(https://www.cnblogs.com/KMould/p/1233481 ...
- Reactor3 中文文档(用户手册)
文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...