Click here to Skip to main content
Click here to Skip to main content

Anonymous methods as event handlers – Part 1

By , 1 Sep 2009
 

The syntactic sugar offered by anonymous methods makes them great candidates for writing event handlers; together with smart type inference, they reduce the amount of code written by an order of magnitude.

And that’s without considering the power offered by closures. With event handlers, closures allow you to kind of “stuff” extra parameters into the handler, without changing the actual number of formal parameters. This blog post shows a situation where an anonymous method acting as an event handler makes code simpler, and then goes on to show a gotcha with un-subscription and anonymous methods.

Here’s a simple Control class that fires a bunch of events.

   1: public void Initialize()
   2: {
   3:     control.KeyPressed += IfEnabledThenDo(control_KeyPressed);
   4:     control.MouseMoved += IfEnabledThenDo(control_MouseMoved);
   5: }
   6:  
   7: public void Destroy()
   8: {
   9:     control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);
  10:     control.MouseMoved -= IfEnabledThenDo(control_MouseMoved);
  11: }

Let’s say you’re developing a GUI application with this class, and you want to handle events only if the originating control is visually enabled i.e., Enabled set to true. Pretty reasonable constraint, but tedious to implement, if you go the standard way of adding the check to the start of each of your event handlers.

   1: class GUIApp
   2: {
   3:     public void Initialize()
   4:     {
   5:         Control control = new Control();
   6:         control.KeyPressed += new EventHandler<control.controleventargs />(control_KeyPressed);
   7:         control.MouseMoved += new EventHandler<control.controleventargs />(control_MouseMoved);
   8:     }
   9:  
  10:     void control_MouseMoved(object sender, Control.ControlEventArgs e)
  11:     {
  12:         if (e.Control.Enabled)
  13:         {
  14:             /// 
  15:         }
  16:     }
  17:  
  18:     void control_KeyPressed(object sender, Control.ControlEventArgsEventArgs e)
  19:     {
  20:         if (e.Control.Enabled)
  21:         {
  22:             ///
  23:         }
  24:     }
  25: }
With an anonymous method, you could write a far more terse and easy to maintain version
   1: class GUIApp
   2: {
   3:     public void Initialize()
   4:     {
   5:         Control control = new Control();
   6:         control.KeyPressed += IfEnabledThenDo(control_KeyPressed);
   7:         control.MouseMoved += IfEnabledThenDo(control_MouseMoved);
   8:     }
   9:  
  10:     public EventHandler<control.controleventargs /> IfEnabledThenDo(EventHandler<control.controleventargs /> actualAction)
  11:     {
  12:         return (sender, args) => { if (args.Control.Enabled) { actualAction(sender, args); } };
  13:     }
  14:  
  15:     void control_MouseMoved(object sender, Control.ControlEventArgs e)
  16:     {
  17:         ///
  18:     }
  19:  
  20:     void control_KeyPressed(object sender, Control.ControlEventArgs e)
  21:     {
  22:         ///
  23:     }
  24: }

IfEnabledThenDo returns an anonymous function that first checks whether the control is enabled before calling the actual function. The code is much shorter, and the condition is checked only in one place, which makes it easy to modify or add additional logic without having to remember to change every single event handler. Plus, the reads like an English statement – subscribe to the event and if enabled, then do whatever else is necessary.

Great, but unless you are a masochist who revels in littering the code base with hard to reproduce bugs that bomb your app only when demoing to your most important customer, you must, of course, write code to unsubscribe. But there’s no method name to refer to, so you do it the same way as you did when subscribing.

   1: public void Initialize()
   2: {
   3:     control.KeyPressed += IfEnabledThenDo(control_KeyPressed);
   4:     control.MouseMoved += IfEnabledThenDo(control_MouseMoved);
   5: }
   6:  
   7: public void Destroy()
   8: {
   9:     control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);
  10:     control.MouseMoved -= IfEnabledThenDo(control_MouseMoved);
  11: }

This, unfortunately, won’t work – the application will still remain subscribed to those events. Can you figure out why?

Answer and more in the next blog post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

S. Senthil Kumar
Software Developer Atmel R&D India Pvt. Ltd.
India India
I'm a 27 yrs old developer working with Atmel R&D India Pvt. Ltd., Chennai. I'm currently working in C# and C++, but I've done some Java programming as well. I was a Microsoft MVP in Visual C# from 2007 to 2009.
 
You can read My Blog here. I've also done some open source software - please visit my website to know more.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralCute Pinmembersupercat91-Sep-09 12:59 
GeneralRe: Cute PinmemberS. Senthil Kumar1-Sep-09 19:23 
GeneralRe: Cute Pinmembersupercat92-Sep-09 5:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130617.1 | Last Updated 1 Sep 2009
Article Copyright 2009 by S. Senthil Kumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid