Manage many events easily with EventHandlerList

There were many little snippets and corners during Juval's class that simply made my day every time. This is one of those.

What happens when you have a class that exposes many events (such as the "Button" or "Control" class that exposes "Click","Focus" etc..)? In the standard case you would have to have many delegates as members inside it and that would make your code look very messy. The Simpler soution however would be to use the EventHandlerList class that is found in the System.ComponentModel namespace. It's basically a hashtable of all the event handlers you want to keep (the delegates, actually) and allows you to use it for general event storing purposes. In fact, the Control class in the .Net framework use this internally to store its own events.

How do you use it? You implement the specific "add" and "remove" accessors for your events, and inside them, you redirect the added or removed delegate value into the EventHandlerList object. Like so:

private EventHandlerList m_handlers = new EventHandlerList();

           

public event EventHandler Saved

 {

   add

   {

    m_handlers.AddHandler("Saved",value);

   }

   remove

   {

    m_handlers.RemoveHandler("Saved",value);

   }

 }

 

 

 

 

Unfortunately, this cannot be done in VB.Net (you can't override event accessors in VB.Net!?).

Here's an implementation of a class that exposes 3 events, one of them is not a simple event handler type. You'll see that it's just as simple to exposes them, but only one member holds all the events.

 

      public class MyComplicatedClass

      {

            public delegate void SpecialEventDelegate(string someText,int someNumber);

 

            private EventHandlerList m_handlers = new EventHandlerList();

           

            public event EventHandler Saved

            {

                  add

                  {

                        m_handlers.AddHandler("Saved",value);

                  }

                  remove

                  {

                        m_handlers.RemoveHandler("Saved",value);

                  }

            }

           

            public event EventHandler Deleted

            {

                  add

                  {

                        m_handlers.AddHandler("Deleted",value);

                  }

                  remove

                  {

                        m_handlers.RemoveHandler("Deleted",value);

                  }

            }

            public event SpecialEventDelegate SpecialEvent

            {

                  add

                  {

                        m_handlers.AddHandler("SpecialEvent",value);

                  }

                  remove

                  {

                        m_handlers.RemoveHandler("SpecialEvent",value);

                  }

            }

           

            private void FireSavedEvent()

            {

                  EventHandler handler = (EventHandler)m_handlers["Saved"];

                  if(handler!=null)

                  {

                        handler(this,new EventArgs());

                  }

            }

           

            private void FireDeletedEvent()

            {

                  EventHandler handler = (EventHandler)m_handlers["Deleted"];

                  if(handler!=null)

                  {

                        handler(this,new EventArgs());

                  }

            }

           

            private void FireSpecialEvent()

            {

                  SpecialEventDelegate handler = (SpecialEventDelegate) m_handlers["SpecialEvent"];

                  int someNumber=3;

                  if(handler!=null)

                  {

                        handler("some text",someNumber);

                  }

            }

      }

 

 

Published Friday, December 31, 2004 1:56 PM by RoyOsherove

Comments

Friday, December 31, 2004 2:11 PM by Duncan Godwin

# re: Manage many events easily with EventHandlerList

Cool!

You can also save on creating a new EventArgs object each time an event is fired by using the EventArgs.Empty object.
Monday, January 03, 2005 1:18 AM by Eric Newton

# re: Manage many events easily with EventHandlerList

EventArgs.Empty probably should do a thread check and return a single eventargs instance per thread... I wonder how this would affect performance?

Or sacrifice the per thread check and EventArgs becomes an AppDomain singleton, maybe eases the GC a little, hmmm...
Tuesday, January 04, 2005 1:49 PM by Paul Vick

# re: Manage many events easily with EventHandlerList

In Whidbey, you'll be able to do this in VB as well. See http://www.panopticoncentral.net/archive/2004/08/06/1545.aspx
Wednesday, January 05, 2005 6:47 PM by Duncan Godwin

# re: Manage many events easily with EventHandlerList

Eric,

EventArgs.Empty follows the Null Object pattern and is a static readonly immutable object so inherently thread-safe. Guid and String use the same pattern.
Saturday, January 08, 2005 1:20 PM by TrackBack

# Custom events in VB.Net

Tuesday, October 03, 2006 6:50 PM by Elad Volpin

# re: Manage many events easily with EventHandlerList

I'm not sure if my comment here is a little late on the subject.... However, according to an article in the MSDN Library, the "pattern" presented in this article, for storing delegates in the EventHandlerList, is for saving up memory allocation. It states that each event causes the compiler to allocate memory to store event information, so if you have a situation where you have multiple events, you'd rather use an EventHandlerList. Here's the link to "How to: Declare Events That Conserve Memory Use". http://msdn2.microsoft.com/en-us/library/yt1k2w4e.aspx Further more, this "pattern" for using the EventHandlerList (also visible by reverse-engineering .NET Control code), states that you should define a "static readonly object" as the key variable. This is probably due to the possibility of saving memory too, in case you're using multiple controls of the same type and you wish to lay low on memory allocated for keys (but this is only an assumption). "How to: Handle Multiple Events Using Event Properties" http://msdn2.microsoft.com/en-us/library/8843a9ch.aspx Therefore, although the article addresses an important subject, the "code look very messy" claim is not an accurate one, because you're still supposed to define multiple "static readonly object" keys, so your code still remains "messy". The actual usage of this pattern is for saving up memory. Finally, this entire comment is written from a "Control development" perspective, so you can clearly state that the example is good enough for the claims given, when discussing "other purposes"... So feel free to completely disregard it... Thanks.

# Ryan’s Tech Blog » EventHandlerList, key equality, and auto-boxing in C#

Pingback from  Ryan’s Tech Blog » EventHandlerList, key equality, and auto-boxing in C#