views:

48

answers:

4

I'm attempting to add an event handler for every control on my form. The form is a simple info box which pops up, and clicking anywhere on it does the same thing (sort of like Outlook's email notifier.) To do this, I've written a recursive method to add a MouseClick handler to each control, as follows:

private void AddMouseClickHandler(Control control, MouseEventHandler handler)
{
    control.MouseClick += handler;
    foreach (Control subControl in control.Controls)
        AddMouseClickHandler(subControl, handler);
}

However, if I wanted to add a handler for all of the MouseDown and MouseUp events, I'd have to write two more methods. I'm sure there's a way around this, but I can't find it. I want a method like:

private void AddRecursiveHandler(Control control, Event event, EventHandler handler)
{
    control.event += handler;
    foreach (Control subControl in control.Controls)
        AddRecursiveHandler(subControl, event, handler);
}
+2  A: 

You could pass the event name as a string and then use Reflection to implement this, but that would be quite ugly (and slow as well). Unfortunately, there is no other way to pass events as arguments to a method.

However, you can write this elegantly using lambda functions. Instead of writing function to add handler, you can write a function that calls a lambda expression for every control:

private void TraverseControls(Control control, Action<Control> f) 
{ 
    f(control); 
    foreach (Control subControl in control.Controls) 
        TraverseControls(subControl, f); 
} 

Then you can solve your original problem using a single call:

TraverseControls(form, ctl => { 
  ctl.MouseDown += handler;
  ctl.MouseUp += handler); });

The lambda expression ctl => { .. } will be called for every control in the tree and inside the lambda expression, you can add handlers to any events of the control. You could also write this using two calls (adding handlers to MouseDown in the first one and to MouseUp in the second one).

Compared to solution using Reflection, this is faster and safer.

Tomas Petricek
+1 Lambdas is a neat solution.
Matthew Ferreira
This works great! Too bad you can't pass events, tho. Lambdas are pretty neat; I'll have to keep them in mind more often.
Daniel Rasmussen
A: 

You can use reflection to hook up to events. Take a look at this article on MSDN

Anero
A: 

It looks like you are on a good path. If you have an event handler in your FORM's MouseDown and MouseUp, you should just be able to attach to that like you already do in your

control.MouseClick += handler... 

just add since the signature is the same, but the action is different, you'll want to handle appropriately.

control.MouseDown += YourFormsMouseDownHandler 
control.MouseUp += YourFormsMouseUpHandler
DRapp
A: 

If you want the event to happen everywhere you do not need to add the event to every item. just add a event to the parent form (or panel if you want just the items in a panel to respond) and everything you click inside that form will fire the event from the parent object.

Scott Chamberlain
This is what I'd really like to do, but it doesn't work. Is there some option I would have to set? I'm just trying `pnlMain.MouseUp += upHandler; pnlMain.MouseDown += downHandler;`
Daniel Rasmussen
I am not 100% sure but I think if a child control handles a event it will not call the parent's event.
Scott Chamberlain
Is there a way to tell a child control *not* to handle the event, so that the parent will?
Daniel Rasmussen