34

Environment: .NET Framework 2.0, VS 2008.

I am trying to create a subclass of certain .NET controls (label, panel) that will pass through certain mouse events (MouseDown, MouseMove, MouseUp) to its parent control (or alternatively to the top-level form). I can do this by creating handlers for these events in instances of the standard controls, e.g.:

public class TheForm : Form
{
    private Label theLabel;

    private void InitializeComponent()
    {
        theLabel = new Label();
        theLabel.MouseDown += new MouseEventHandler(theLabel_MouseDown);
    }

    private void theLabel_MouseDown(object sender, MouseEventArgs e)
    {
        int xTrans = e.X + this.Location.X;
        int yTrans = e.Y + this.Location.Y;
        MouseEventArgs eTrans = new MouseEventArgs(e.Button, e.Clicks, xTrans, yTrans, e.Delta);
        this.OnMouseDown(eTrans);
    }
}

I cannot move the event handler into a subclass of the control, because the methods that raise the events in the parent control are protected and I don't have a qualifier for the parent control:

Cannot access protected member System.Windows.Forms.Control.OnMouseDown(System.Windows.Forms.MouseEventArgs) via a qualifier of type System.Windows.Forms.Control; the qualifier must be of type TheProject.NoCaptureLabel (or derived from it).

I am looking into overriding the WndProc method of the control in my sub-class, but hopefully someone can give me a cleaner solution.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
GentlemanCoder
  • 547
  • 1
  • 5
  • 11

3 Answers3

70

Yes. After a lot of searching, I found the article "Floating Controls, tooltip-style", which uses WndProc to change the message from WM_NCHITTEST to HTTRANSPARENT, making the Control transparent to mouse events.

To achieve that, create a control inherited from Label and simply add the following code.

protected override void WndProc(ref Message m)
{
    const int WM_NCHITTEST = 0x0084;
    const int HTTRANSPARENT = (-1);

    if (m.Msg == WM_NCHITTEST)
    {
        m.Result = (IntPtr)HTTRANSPARENT;
    }
    else
    {
        base.WndProc(ref m);
    }
}

I have tested this in Visual Studio 2010 with .NET Framework 4 Client Profile.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
akatran
  • 1,057
  • 9
  • 15
  • Thanks akatran-- I have moved on so far I don't even remember how I resolved this issue myself, but it looks like you nailed it. – GentlemanCoder Jan 12 '12 at 17:04
  • Thank you very much, this helped me as well - clear, concise, and solves the problem! – Eric Jun 17 '12 at 22:18
  • 1
    It is worth noting that this takes the false transparent controls out of the event loop - they don't get a chance to handle the MouseMove event themselves because it drills directly to the parent's handler. To retain the ability for each control itself to also handle the event before passing it up to the parent you can do something like this : http://stackoverflow.com/a/14814756/327083 – J... Feb 12 '13 at 17:40
  • 1
    BTW, changing the condition to `(m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEHOVER)` allowed mouse over behavior to pass through to the control underneath as well in my case. Perhaps that helps somebody else as well. – jpierson Jul 14 '16 at 03:24
5

The WS_EX_TRANSPARENT extended window style actually does this (it's what in-place tooltips use). You might want to consider applying this style rather than coding lots of handlers to do it for you.

To do this, override the CreateParams method:

protected override CreateParams CreateParams
{
  get
  {
    CreateParams cp=base.CreateParams;
    cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT
    return cp;
  }
}

For further reading:

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
2

You need to write a public/protected method in your base class which will raise the event for you. Then call this method from the derived class.

OR

Is this what you want?

public class MyLabel : Label
{
    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        //Do derived class stuff here
    }
}
Sandeep Datta
  • 28,607
  • 15
  • 70
  • 90
  • I don't think so. OnMouseDown *raises* the event, it does not handle it. I need an event handler that passes the event to it's parent. And I can't do your first suggestion b/c the base class is a standard Windows control, not a class that I wrote. – GentlemanCoder Feb 13 '09 at 19:14
  • @SandeepDatta, Parent control and base class are different, right ? – Kira Aug 08 '16 at 08:39