【问题标题】:make VisualTreeHelper.HitTest work in a unit test?让 VisualTreeHelper.HitTest 在单元测试中工作?
【发布时间】:2013-06-10 21:07:08
【问题描述】:

我想在某些形状上使用 WPF HitTest 功能,而不在屏幕上显示它们。这可能吗?这段代码不像我预期的那样工作。我该如何完成这项工作?

[Test, Ignore, RequiresSTA]
public void VerifyFillContains()
{
    // make a simple triangle:
    var seg1 = new System.Windows.Media.LineSegment(new Point(0.2, 0.1), false);
    var seg2 = new System.Windows.Media.LineSegment(new Point(0.3, 0.8), false);
    var figure = new PathFigure(new Point(0.7, 0.5), new List<PathSegment>{seg1, seg2}, true);

    var sg = new PathGeometry();
    sg.Figures.Add(figure);

    if (sg.CanFreeze)
        sg.Freeze();

    // these don't work:
    Assert.IsFalse(sg.FillContains(new Point()));
    Assert.IsFalse(sg.FillContains(new Point(1.0, 1.0)));
    Assert.IsTrue(sg.FillContains(new Point(0.5, 0.5)));

    var path = new Path { Data = sg, Fill = Brushes.Black };
    path.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    path.Arrange(new Rect(path.DesiredSize));

    // and these don't work:
    var result = VisualTreeHelper.HitTest(path, new Point(0.0, 0.0));
    Assert.IsFalse(result != null && Equals(result.VisualHit, path));
    result = VisualTreeHelper.HitTest(path, new Point(1.0, 1.0));
    Assert.IsFalse(result != null && Equals(result.VisualHit, path));
    result = VisualTreeHelper.HitTest(path, new Point(0.5, 0.5));
    Assert.IsTrue(result != null && Equals(result.VisualHit, path));
}

【问题讨论】:

    标签: c# wpf nunit hittest


    【解决方案1】:

    命中测试基于元素的渲染,因此您应该测量和排列形状。例如

    shape.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    shape.Arrange(new Rect(shape.DesiredSize));
    

    或者您可以只使用几何的FillContains 方法。例如

    var result = shape.Data.FillContains(ToPoint(target));
    

    【讨论】:

    • 这是很棒的信息! Measure/Arrange 确实消除了 HitTest 上的空结果。不幸的是,它在我的场景中仍然不起作用。这两种方法都会返回误报,我不明白为什么。我需要将我的点从某个绝对坐标转换为局部坐标吗?
    • 是的,命中测试将与元素相关。我认为 HitTest 将基于元素的实际大小,基于元素的测量/排列方式(即它是否被拉伸)。我认为 FillContains 将基于几何的自然大小。
    • 我已经更新了示例代码以使用您的建议,但表明它仍然不起作用。
    • 您使用的值非常小。我猜是宽容。取点的 FillContains 的重载将 StandardFlatningTolerance 传递给采用公差和公差类型的重载,StandardFlatningTolerance 为 0.25。如果您使用较小的容差,则该方法将返回 false,正如您对 new Point() 所期望的那样。另一种选择是增加您正在使用的值。所以如果你把你的样本乘以 10,那么它也可以工作。
    • 是的,宽容要了我的命!有没有办法在 VisualTreeHelper 上设置它?我没有看到任何明显的东西。
    【解决方案2】:

    我认为您的 CreateWpfShapeFromList 必须将 AddVisualChild 方法实现到您的形状的可视子项。

    因为我反映了 VisualTreeHelper 并发现 HitTest 在内部使用 GetVisualChild,所以试试我的解决方案。

    【讨论】:

    • 另外,如果您的孩子不是从 DrawingVisual 继承的,您必须覆盖 Measure & Arrage。请注意。
    • 请看我更新的示例代码。我看不出 AddVisualChild 与它有什么关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多