I have a panel in my Form with a click event handler. I also have some other controls inside the panel (label, other panels, etc.). I want the click event to register if you click anywhere inside the panel. The click event works as long as I don't click on any of the controls inside the panel but I want to fire the event no matter where you click inside the panel. Is this possible without adding the same click event to all of the controls inside the panel?
-
1No, just a regular windows forms application – Scott Chantry Oct 13 '10 at 18:26
5 Answers
Technically it is possible, although it is very ugly. You need to catch the message before it is sent to the control that was clicked. Which you can do with IMessageFilter, you can sniff an input message that was removed from the message queue before it is dispatched. Like this:
using System;
using System.Drawing;
using System.Windows.Forms;
class MyPanel : Panel, IMessageFilter {
public MyPanel() {
Application.AddMessageFilter(this);
}
protected override void Dispose(bool disposing) {
if (disposing) Application.RemoveMessageFilter(this);
base.Dispose(disposing);
}
public bool PreFilterMessage(ref Message m) {
if (m.HWnd == this.Handle) {
if (m.Msg == 0x201) { // Trap WM_LBUTTONDOWN
Point pos = new Point(m.LParam.ToInt32());
// Do something with this, return true if the control shouldn't see it
//...
// return true
}
}
return false;
}
}

- 922,412
- 146
- 1,693
- 2,536
-
+1 I have also done this and agree it should work nicely. My only warning is that it essentially attaches to the applications event message pump, so make sure that whatever you do in the "Do something with this..." bit, make it fast and efficient. – Neil Fenwick Oct 13 '10 at 19:46
-
1Meh, it is already filtered for the panel and the message. This code runs at human time. – Hans Passant Oct 13 '10 at 19:57
-
This seems to only work when the panel itself is clicked, but not the controls on the panel (because of `m.HWnd == this.Handle`?) Am I missing something? – 41686d6564 stands w. Palestine Oct 05 '20 at 16:51
-
@Hans It seems that something like [this](https://stackoverflow.com/a/19089507/8967612) needs to be done, and that's what I went with for now. Please correct me if I'm wrong; I really appreciate it! – 41686d6564 stands w. Palestine Oct 05 '20 at 17:36
I needed the exact same functionality today, so this is tested and works:
1: Create a subclasser which can snatch your mouseclick:
internal class MessageSnatcher : NativeWindow
{
public event EventHandler LeftMouseClickOccured = delegate{};
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_PARENTNOTIFY = 0x210;
private readonly Control _control;
public MessageSnatcher(Control control)
{
if (control.Handle != IntPtr.Zero)
AssignHandle(control.Handle);
else
control.HandleCreated += OnHandleCreated;
control.HandleDestroyed += OnHandleDestroyed;
_control = control;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PARENTNOTIFY)
{
if (m.WParam.ToInt64() == WM_LBUTTONDOWN)
LeftMouseClickOccured(this, EventArgs.Empty);
}
base.WndProc(ref m);
}
private void OnHandleCreated(object sender, EventArgs e)
{
AssignHandle(_control.Handle);
}
private void OnHandleDestroyed(object sender, EventArgs e)
{
ReleaseHandle();
}
}
2: Initialize the snatcher to hook into the panel WndProc:
private MessageSnatcher _snatcher;
public Form1()
{
InitializeComponent();
_snatcher = new MessageSnatcher(this.panel1);
}
3: The Message snatcher will get the WM_PARENTNOTIFY if you click on a child control.

- 9,208
- 8
- 50
- 73
You used to be able to override the OnBubbleEvent method on the control. In WPF the mechanism is called Routed events : http://weblogs.asp.net/vblasberg/archive/2010/03/30/wpf-routed-events-bubbling-several-layers-up.aspx

- 56
- 3
Bit late to the party, But What I did was to map all the click event of all the controls inside of the panel to panel click event. I know its nasty approach. but hey!!

- 101
- 2
a simple solution: every control inside the usercontrol gets the same click-event "ControlClick". The usercontrol event click works with any controls inside.
private void ControlClick(Object sender, EventArgs e)
{
if (sender is UC_Vorgang uC_vorgang)
{
uC_vorgang.OnClick(e);
}
else
{
ControlClick(((Control)sender).Parent, e);
}
}

- 1