【问题标题】:Why is the hit test position of a TextBox on a Canvas different from it's actual position?为什么 Canvas 上 TextBox 的命中测试位置与其实际位置不同?
【发布时间】:2012-12-13 23:38:19
【问题描述】:

我有一个画布,上面有几个元素,比如线条、路径和文本框。在 Canvas 的 MouseOver 事件中,所有这些事件都有一个 HitTest,例如:

bool HitTest( Point p )
{
  return VisualTreeHelper.HitTest( textBox, p ) != null;
}

这适用于线条和路径的像素精度,但不适用于文本框。

例如当TextBox定位在50时,50是这样的:

Canvas.SetLeft( textBox, 50.0 );
Canvas.SetTop( textBox, 50.0 );

它在该位置正确绘制:如果文本高约 20 像素,宽约 50 像素,则屏幕上的边界矩形大致为 L=50 T=50 R=100 B=70。

但是,HitTest 函数在该矩形中返回 false,并且仅在矩形 L=0 T=0 R=50 B=20 中返回 true。换句话说,命中测试知道文本框的大小,但忽略它不是位于 0,0。

为什么会发生这种情况,如何解决? (我感觉这与我不使用 SetLeft/SetTop 定位 Line 和 Path 元素有关)

【问题讨论】:

    标签: wpf canvas textbox hittest


    【解决方案1】:

    仅仅是因为 TextBox 对它位于 Canvas 中的事实一无所知,因此对“实际位置”一无所知。

    当您调用VisualTreeHelper.HitTest(textBox, p) 时,点p 以相对于textBox 视觉对象的坐标给出。 TextBox 位于 Canvas 或任何其他可能的容器中的哪个位置无关紧要。

    您获得 Line 和 Path 的“正确”坐标(相对于您的 Canvas)仅仅是因为您没有在它们上设置 Canvas.Left 或 Canvas.Top。

    如果你需要相对于画布的坐标,你通常会这样做:

    bool HitTest(UIElement element, Point p)
    {
        var elementPoint = new Point(
            p.X - Canvas.GetLeft(element),
            p.Y - Canvas.GetTop(element));
    
        return VisualTreeHelper.HitTest(element, elementPoint) != null;
    }
    

    或者

    bool HitTest(UIElement element, Point p)
    {
        var elementPoint = canvas.TransformToDescendant(element).Transform(p);
    
        return VisualTreeHelper.HitTest(element, elementPoint) != null;
    }
    

    【讨论】:

    • 所以唯一的解决方法是从点中减去左/上坐标以进行命中测试?
    • 不错,不知道 TransformToDescendant
    • TransformToDescendent 还具有适用于任何容器控件的优点,而不仅仅是 Canvas。
    猜你喜欢
    • 2019-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    相关资源
    最近更新 更多