在可视化容器里通常需要DrawVisual对象画东西
如果需要知道是否选择了DrawVisual需要使用可视化树的命中测试
简单案例
cs
如果点中了可视化对象
public DrawingVisual? GetVisual(Point point)
{
HitTestResult result = VisualTreeHelper.HitTest(this, point);
return result.VisualHit as DrawingVisual;
}
获取区域中的可视化对象
cs
public List<DrawingVisual> GetVisuals(Geometry region)
{
hits.Clear();
HitTestResultCallback callback = new HitTestResultCallback(HitTestCallback);//回调
GeometryHitTestParameters parameters = new GeometryHitTestParameters(region);
//命中测试
VisualTreeHelper.HitTest(this,null, callback, parameters);
return hits;
}
/// <summary>
/// 回调方法。命中到的小方格添加到hits
/// </summary>
/// <param name="result">命中测试结果</param>
/// <returns></returns>
private HitTestResultBehavior HitTestCallback(HitTestResult result)
{
GeometryHitTestResult geometryResult = (GeometryHitTestResult)result;
DrawingVisual visual= result.VisualHit as DrawingVisual;
if (visual != null && geometryResult.IntersectionDetail== IntersectionDetail.FullyInside)
{
hits.Add(visual);
return HitTestResultBehavior.Stop;
}
return HitTestResultBehavior.Continue;
}
VisualTreeHelper.HitTest(this,null, callback, parameters);

这里主要讲筛选回调

cs
//如果是Canvas跳过
private HitTestFilterBehavior HitTestFilter(DependencyObject o)
{
Type type = o.GetType();
switch (type.Name) {
case "Canvas":
return HitTestFilterBehavior.ContinueSkipSelf;
default:
return HitTestFilterBehavior.Continue;
}
}

重写默认命中测试
可以通过重写 HitTestCore 方法重写视觉对象的默认命中测试支持。 这意味着,在调用 HitTest 方法时,将调用 HitTestCore 的替代实现。 当命中测试落在视觉对象的边框内时,将调用重写的方法,即使坐标落在视觉对象呈现内容之外也是如此。
cs
// Override default hit test support in visual object.
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
// Perform actions based on hit test of bounding rectangle.
// ...
// Return results of base class hit testing,
// which only returns hit on the geometry of visual objects.
return base.HitTestCore(hitTestParameters);//使用默认的
//return new PointHitTestResult(this, pt);
}
例子 自定义return new PointHitTestResult(this, pt);
public class MyCircleButton : Button
{
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
// 1. 获取命中点(相对当前控件)
Point pt = hitTestParameters.HitPoint;
// 2. 自定义命中判断:是否在圆形区域内(控件中心为圆心,半径为控件最小边长的一半)
Point center = new Point(this.ActualWidth / 2, this.ActualHeight / 2);
double radius = Math.Min(this.ActualWidth, this.ActualHeight) / 2;
double distance = Math.Sqrt(Math.Pow(pt.X - center.X, 2) + Math.Pow(pt.Y - center.Y, 2));
// 3. 满足自定义条件,强制返回命中结果;否则沿用默认逻辑(或返回null)
if (distance <= radius)
{
// 强制指定当前圆形按钮为命中目标
return new PointHitTestResult(this, pt);
}
else
{
// 不满足条件时,沿用默认逻辑(或返回null表示未命中)
return base.HitTestCore(hitTestParameters);
}
}
}