14

I need to find the control under the mouse, within an event of another control. I could start with GetTopLevel and iterate down using GetChildAtPoint, but is there a quicker way?

Simon
  • 25,468
  • 44
  • 152
  • 266
  • Why do you need to start at GetTopLevel, couldn't you simply go to GetChildAtPoint directly? – Marcus L Feb 25 '09 at 15:35
  • (a) The control under the mouse isn't necessarily a child of the control whose event is firing, and (b) I would still have to iterate down to find the innermost control. – Simon Feb 25 '09 at 15:36

2 Answers2

21

This code doesn't make a lot of sense, but it does avoid traversing the Controls collections:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pnt);

private void Form1_MouseMove(object sender, MouseEventArgs e) {
  IntPtr hWnd = WindowFromPoint(Control.MousePosition);
  if (hWnd != IntPtr.Zero) {
    Control ctl = Control.FromHandle(hWnd);
    if (ctl != null) label1.Text = ctl.Name;
  }
}

private void button1_Click(object sender, EventArgs e) {
  // Need to capture to see mouse move messages...
  this.Capture = true;
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Makes perfect sense to me. :-) WindowFromPoint grabs the window handle directly under the mouses position on the screen, regardless of containment. Control.FromHandle translates it into a .Net control (if possible). Boom, done. Very slick. – Jason D Mar 11 '10 at 14:25
  • Would it not be easier to simulate the mouse click? You can find a link [here](http://stackoverflow.com/questions/2416748/how-to-simulate-mouse-click-in-c) – Pimenta Oct 24 '12 at 17:32
  • What if I want to get the control of another application& – r.mirzojonov Sep 07 '14 at 18:53
  • POINT pt; HWND hwnd; GetCursorPos (&pt); //find the control or window that lies underneath the mouse cursor. hwnd= WindowFromPoint (pt); – MathArt Oct 27 '21 at 07:03
2

Untested and off the top of my head (and maybe slow...):

Control GetControlUnderMouse() {
    foreach ( Control c in this.Controls ) {
        if ( c.Bounds.Contains(this.PointToClient(MousePosition)) ) {
             return c;
         }
    }
}

Or to be fancy with LINQ:

return Controls.Where(c => c.Bounds.Contains(PointToClient(MousePosition))).FirstOrDefault();

I'm not sure how reliable this would be, though.

Lucas Jones
  • 19,767
  • 8
  • 75
  • 88
  • I just used this, it's great to get *every* control under a mouse position. However, it should be c.Bounds.Contains(Point p) not c.Bounds.IntersectsWith(Rectangle r). – snicker Oct 19 '09 at 22:54
  • `MousePosition` will return a new `point` at each call which is not good for performance, it is better to cache that or better `PointToClient(MousePosition)` into a variable in your loop – S.Serpooshan Sep 25 '18 at 10:02