One little problem is that a form is normally covered by other controls, children of the form, so it won't get mouse events dispatched to it (in contrast to keyboard events, by the way). So, you can artificially "bubble" some other event to the form. This is pretty easy to do.
For simplicity, let's assume you write all the relevant code in just one class, some
Form
class. Create some event arguments class, derived from
System.EventArgs
. Main property it needs is the reference to the control which was the original event target (the control a mouse clicks on). Add a control instance to your form.
Subscribe to some mouse event on all the control of the form. This is done by recursively traversing all the control and adding the handler to each instance. It's better to subscribe to
MouseDown
not
Click
, because
Click
— surprise! — is not a mouse event; it is a higher-level "logical" event invoked by either mouse or keyboard. In this event handler, common for all those controls, invoke the event defined as described in the previous paragraph. Pass the first event argument ("sender") of the handled event to the "original event target" property of the invoked event. In other words, you get a sender from a mouse event you handle and redirect this data to the event instance you invoke on the form.
This way, any handler added to the invocation list of the forms event you define will get a notification that on some child control the mouse even was invoked, and tell you on what child control. Then compare the reference of this child control with the reference to the user control in your question. If these are different object, it mean that the user clicked outside of your user control. Simple, isn't it.
I mean, it's simple. Please try to write this simple code; it will be just few lines. But if something is unclear or seems to be difficult, please ask your questions; then I'll show you more detail. Please be specific. But I hope you can do it right away.
Let's consider one simple example:
[EDIT]
First, let's define some event arguments class:
class ClickFormControlEventArgs : System.EventArgs {
internal ClickFormControlEventArgs(Control originalTarget) {
this.OriginalTarget = originalTarget;
}
internal Control OriginalTarget { get; private set; }
}
Now, the form, any form, main or not:
public partial class MainForm : Form {
void AddMouseDownEventHandler(Control control, MouseEventHandler handler) {
control.MouseDown += handler;
foreach (Control child in control.Controls)
AddMouseDownEventHandler(child, handler);
}
public MainForm() {
InitializeComponent();
Text = Application.ProductName;
AddMouseDownEventHandler(this, (sender, eventArgs) => {
if (FormControlClicked != null) {
Control control = (Control)sender;
FormControlClicked.Invoke(
sender,
new ClickFormControlEventArgs(control));
}
});
}
internal event System.EventHandler<ClickFormControlEventArgs>
FormControlClicked;
}
Now, each event handler added to the invocation list of the form's even instance
FormControlClicked
will get notification of some. For general example, I'll show some code outside the form class, assuming that we have the instance of the form with this event. In case you do it inside the form class, it could be some method where the instance of the form is "this" (instead of "form" in the code below).
Control control =
Form form =
form.FormControlClicked += (sender, eventArgs) => {
if (eventArgs.OriginalTarget == control) {
} else if (eventArgs.OriginalTarget == form) {
} else {
}
}
Now, look at the objections by Philippe Mori who concerned about disruption in usual event handling of other events on all those controls, higher-level relative to this
MouseDown
. No, it won't be a problem, because you never set an event handler and never block other event handler or event propagation. Other event handler will do their usual work and different event handlers won't interfere.
—SA