Catching a Contained Control's Mouse Events in a UserControl
I have a UserControl
that contains another UserControl
. I'd like the containing control to be able to handle any mouse events that happen over the contained control's area. What's the easiest way to do this?
Changing code for the contained control is possible, but only as a last resort. The contained control has a window that is controlled by an unmanaged library.
FWIW, I have tried adding handlers for the contained control's mouse events, but those handlers never get called. I suspect the contained control is consuming the mouse events.
I've considered adding some sort of transparent window on top of the co开发者_如何学编程ntained control, to catch the events, but I'm still pretty new to Windows Forms and I'm wondering if there is a better way.
If the inside control is not sealed, you may want to subclass it and override the mouse-related methods:
protected override void OnMouseClick(MouseEventArgs e) {
//if you still want the control to process events, uncomment this:
//base.OnMouseclick(e)
//do whatever
}
etc.
Well, it's technically possible. You have to redirect the mouse message yourself, that requires a bit of P/Invoke. Paste this code into your inner UserControl class:
protected override void WndProc(ref Message m) {
// Re-post mouse messages to the parent window
if (m.Msg >= 0x200 && m.Msg <= 0x209 && !this.DesignMode && this.Parent != null) {
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
// Fix mouse position to be relative from parent's client rectangle
pos = this.PointToScreen(pos);
pos = this.Parent.PointToClient(pos);
IntPtr lp = (IntPtr)(pos.X + pos.Y << 16);
PostMessage(this.Parent.Handle, m.Msg, m.WParam, lp);
return;
}
base.WndProc(ref m);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
This is best avoided btw. The parent control should probably just subscribe to the inner control's mouse events.
Here's what I did:
First, I defined a TransparentControl
class, which is simply a control that is transparent and doesn't draw anything. (This code is thanks to https://web.archive.org/web/20141227200000/http://bobpowell.net/transcontrols.aspx .)
public class TransparentControl : Control
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
protected override void OnPaint(PaintEventArgs pe)
{
// Do nothing
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// Do nothing
}
}
Then, I placed a TransparentControl
in my user control on top of the contained user control, and added handlers for its mouse events.
精彩评论