我们有时候又需求从当前视觉树中找一些东西,比如鼠标按下的时候,看看鼠标下的元素都有什么。又比如某块区域下有哪些元素?某个坐标点下有哪些元素?

  这些需求在使用 命中测试的时候,可以非常方便和快速的去找到我们需要的内容。

简单命中测试

  我们写一个最简单的命中测试的示例,来了解命中测试。我在一个画板上在不同的位置放了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技巧:命中测试在视觉树中的使用的更多相关文章

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

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

  2. WPFの命中测试

    概述:  WPF中的Canvas是常用的一个绘图控件,可以方便地在Canvas中添加我们需要处理的各种元素如:图片.文字等.但Canvas中元素增加到一定数量,并且有重合的时候,我们如何通过在Canv ...

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

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

  4. wpf datagrid row的命中测试

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

  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. 分页技巧_测试并继续改进分页用的QueryHelper辅助对象

    分页技巧_测试并继续改进分页用的QueryHelper辅助对象 QueryHelper.java /** * 用于辅助拼接HQL语句 */ public class QueryHelper { pri ...

  8. WPF技巧-Canvas转为位图

    转自:http://www.cnblogs.com/tmywu/archive/2010/09/14/1825650.html 在WPF中我们可以将Canvas当成一种画布,将Canvas中的控件当成 ...

  9. WPF 一个数据库连接测试的实现

    要实现的功能效果图如下:因为我们要测试数据是从输入框获得的,所以,我们的连接字符串不是写死在应用程序中的.下面我就详细介绍一下.

随机推荐

  1. 【Microstation】三维建模基础及软件入门到精通实验教程目录

    @ 目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 MicroStation是一款非常不错的二维和三维设计软件,由奔特力(Bentley)工程软件系统有限公司开发的一款软件.在C ...

  2. WEB页面下载内容导出excel

    internal class DownloadHandler : IDownloadHandler    {        public DownloadHandler()        {      ...

  3. 贪心算法leetcode-763

    int[] lastShow = new int[26]; var list = new LinkedList<Integer>(); for (int i = 0; i < s.l ...

  4. GO学习-(20) Go语言基础之单元测试

    Go语言基础之单元测试 不写测试的开发不是好程序员.我个人非常崇尚TDD(Test Driven Development)的,然而可惜的是国内的程序员都不太关注测试这一部分. 这篇文章主要介绍下在Go ...

  5. Step By Step(Lua编译执行与错误)

    Step By Step(Lua编译执行与错误) 1. 编译:    Lua中提供了dofile函数,它是一种内置的操作,用于运行Lua代码块.但实际上dofile只是一个辅助函数,loadfile才 ...

  6. TVMNN编译Compiler栈

    TVMNN编译Compiler栈 内容纲要 前言 调研目标 TVM介绍 TVM源码架构 FrontEnd Relay BackEnd VTA实现原理及设计思想提炼 整体结构 VTA Hardware ...

  7. GPU加速:宽深度推理

    GPU加速:宽深度推理 Accelerating Wide & Deep Recommender Inference on GPUs 推荐系统推动了许多最流行的在线平台的参与.随着为这些系统提 ...

  8. httprunner中的分层(api、testcase、testsuite)及实际使用

    一.分层思想 api定义层:最底下的一层是api的定义层testcase层:测试用例层,调用定义层的内容testsuite:测试套件层 二.分层案例设计实现实践举例 1.api 层: 2.testca ...

  9. Django(58)viewsets视图集详解

    前言 ViewSet 只是一种基于类的视图,它不提供任何方法处理程序(如 .get()或.post()),而是提供诸如.list()和 .create() 之类的操作. ViewSet 的方法处理程序 ...

  10. 1-3. SpringBoot基础,Java配置(全注解配置)取代xml配置

    最近突发奇想,整合一下以前一些学习笔记,分享自己这几年爬过的坑,逐步更新文章,谢谢大家的关注和支持. 这节讲一下SpringBoot的学习必须的一些基础,Java配置.其实在Spring2.0时代就已 ...