Pass-through mouse events to parent control

60,438

Solution 1

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.

Solution 2

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:

Solution 3

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
    }
}
Share:
60,438
GentlemanCoder
Author by

GentlemanCoder

Updated on August 31, 2020

Comments

  • GentlemanCoder
    GentlemanCoder over 3 years

    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.

  • GentlemanCoder
    GentlemanCoder over 15 years
    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
    GentlemanCoder over 15 years
    Thanks for the suggestion. I tried it and it does not work in my case. Perhaps it only works for top level windows?
  • GentlemanCoder
    GentlemanCoder over 12 years
    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.
  • Eric
    Eric almost 12 years
    Thank you very much, this helped me as well - clear, concise, and solves the problem!
  • J...
    J... over 11 years
    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 : stackoverflow.com/a/14814756/327083
  • jpierson
    jpierson almost 8 years
    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.
  • Kira
    Kira almost 8 years
    @SandeepDatta, Parent control and base class are different, right ?