I have a c# form (let\'s call it MainForm) with a number of custom controls on it. I\'d like to have the MainForm.OnClick() method fire anytime someone clicks on the form re
This is a common pattern in development, its called the Observer pattern. There are lots of examples of Observer patterns and c# here is 1 example http://msdn.microsoft.com/en-us/library/ms954621.aspx but have a good google around.
I recommend creating a base form for the other forms in your application to inherit. Add this code to your base form to create a new event called GlobalMouseClickEventHandler:
namespace Temp
{
public delegate void GlobalMouseClickEventHander(object sender, MouseEventArgs e);
public partial class TestForm : Form
{
[Category("Action")]
[Description("Fires when any control on the form is clicked.")]
public event GlobalMouseClickEventHander GlobalMouseClick;
public TestForm()
{
InitializeComponent();
BindControlMouseClicks(this);
}
private void BindControlMouseClicks(Control con)
{
con.MouseClick += delegate(object sender, MouseEventArgs e)
{
TriggerMouseClicked(sender, e);
};
// bind to controls already added
foreach (Control i in con.Controls)
{
BindControlMouseClicks(i);
}
// bind to controls added in the future
con.ControlAdded += delegate(object sender, ControlEventArgs e)
{
BindControlMouseClicks(e.Control);
};
}
private void TriggerMouseClicked(object sender, MouseEventArgs e)
{
if (GlobalMouseClick != null)
{
GlobalMouseClick(sender, e);
}
}
}
}
This solution will work not only for top-level controls, but also nested controls such as controls placed inside of panels.
You can hook all the control's events, if you like, and then monitor that way. I assume there is some uber fancy Win32 api way to trap them all, but that is beyond me at the moment.
public Form1()
{
InitializeComponent();
HookEvents();
}
private void HookEvents() {
foreach (Control ctl in this.Controls) {
ctl.MouseClick += new MouseEventHandler(Form1_MouseClick);
}
}
void Form1_MouseClick(object sender, MouseEventArgs e)
{
LogEvent(sender, "MouseClick");
}
// and then this just logs to a multiline textbox you have somwhere on the form
private void LogEvent(object sender, string msg) {
this.textBox1.Text = string.Format("{0} {1} ({2}) \n {3}",
DateTime.Now.TimeOfDay.ToString(),
msg,
sender.GetType().Name,
textBox1.Text
);
}
The output is something like this, showing all the events and who "sent" them up:
14:51:42.3381985 MouseClick (Form1)
14:51:40.6194485 MouseClick (RichTextBox)
14:51:40.0100735 MouseClick (TextBox)
14:51:39.6194485 MouseClick (Form1)
14:51:39.2131985 MouseClick (RichTextBox)
14:51:38.8694485 MouseClick (Button)
HTH.
Catching a click on an open space on the form is easy, but to get a click that's actually on a control, you'll need the cooperation of that control to send it to the form.
One possibility is to place a transparent control over the entire form, and accept clicks onto that, deal with them, and then pass them onto the proper control underneath.
In the form's ControlAdded event, add a MouseClick handler to the control, with the Address of the form's click event. I haven't tested this, but it might work.
Private Sub Example_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlAdded
AddHandler e.Control.MouseClick, AddressOf Example_MouseClick
End Sub
Private Sub Example_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
MessageBox.Show("Click")
End Sub
The only way I've ever managed to do this is to handle the [c]Click[/c] event of every control. I don't believe the event is raised before the control processes it.
In WPF, there are "tunneling" preview events that provide this functionality, but that doesn't really help you in WinForms.