5

I have Labels inside a Canvas, I need to get the label that intersects with coordinates X,Y?

Thanks!!

Mahbub
  • 4,812
  • 1
  • 31
  • 34

2 Answers2

6

Simply use InputHitTest on your canvas, passing the coordinate you want as parameter. Note that InputHitTest is available on every UIElement and is not specific to canvas.

Julien Lebosquain
  • 40,639
  • 8
  • 105
  • 117
  • I don't think this gets all elements if the X,Y point overlaps more than one child. – Ed Bayiates Jul 21 '11 at 19:55
  • You're right, this doesn't (the question implies it's not needed though "get the label"). However it will take into account margins and z-order, layout rounding, ... – Julien Lebosquain Jul 21 '11 at 20:03
  • True. +1 for the simplicity of it. – Ed Bayiates Jul 21 '11 at 20:09
  • Argh, I've spent so much time trying to churn out a nice working example. Some caveats though, the hit test will return leaves of the visual tree. So it won't return the Label, but the TextBlock (or other) that is presenting the content. Using the [`VisualTreeHelper.HitTest()`](http://msdn.microsoft.com/en-us/library/ms608753.aspx) method is supposed to help with this but has another problem, it will actually skip the labels in the hit test. The solution I've found (which took up most of my time) is to [search the visual tree ourselves](http://stackoverflow.com/questions/3411910). – Jeff Mercado Jul 21 '11 at 20:49
  • 4
    You can use the HitTesting in WPF To traverse through multiple items, even if they overlap. You use VisualTreeHelper.HitTest with a callback. For an example, take a look at this SO answer's hit test code: http://stackoverflow.com/questions/6410146/dockable-windows-floating-window-and-mainwindow-menu-integration/6770950#6770950 – NathanAW Jul 21 '11 at 20:50
  • 1
    @Nathan: Though subject to the problem that I mentioned in my previous comment. – Jeff Mercado Jul 21 '11 at 22:08
3

Canvas.GetLeft(element), Canvas.GetTop(element) will get you any element's position. Use ActualWidth and ActualHeight to form its complete rectangle. You can iterate through the Children of the Canvas with a foreach.

Edit: CodeNaked pointed out that elements might be set with SetRight or SetBottom so I modified the sample code:

foreach (FrameworkElement nextElement in myCanvas.Children)
{
    double left = Canvas.GetLeft(nextElement);
    double top = Canvas.GetTop(nextElement);
    double right = Canvas.GetRight(nextElement);
    double bottom = Canvas.GetBottom(nextElement);
    if (double.IsNaN(left))
    {
        if (double.IsNaN(right) == false)
            left = right - nextElement.ActualWidth;
        else
            continue;
    }
    if (double.IsNaN(top))
    {
        if (double.IsNaN(bottom) == false)
            top = bottom - nextElement.ActualHeight;
        else
            continue;
    }
    Rect eleRect = new Rect(left, top, nextElement.ActualWidth, nextElement.ActualHeight);
    if (myXY.X >= eleRect.X && myXY.Y >= eleRect.Y && myXY.X <= eleRect.Right && myXY.Y <= eleRect.Bottom)
    {
        // Add to intersects list
    }
}
Ed Bayiates
  • 11,060
  • 4
  • 43
  • 62
  • You're assuming the OP is not using the [Right](http://msdn.microsoft.com/en-us/library/system.windows.controls.canvas.right.aspx) or [Bottom](http://msdn.microsoft.com/en-us/library/system.windows.controls.canvas.bottom.aspx) attached properties. – CodeNaked Jul 21 '11 at 19:51
  • @CodeNaked: The comments in the question state they are looking based on Top Left. – Scott Boettger Jul 21 '11 at 19:53
  • @Scott - The comment says the X/Y coordinate are relative to the top-left, not that he's using the Top and Left attached properties. Either way I up voted this answer, since it's on the mark. – CodeNaked Jul 21 '11 at 19:56
  • @AresAvatar - Uh, no it doesn't. Each attached property is used differently in the Canvas.ArrangeOverride. Setting the Right attached property doesn't affect the Left property. – CodeNaked Jul 21 '11 at 19:59
  • Thanks! I wonder why there is no function for that in WPF like hitTest! –  Jul 21 '11 at 23:45