CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jean-Paul S. Boodhoo

Develop With Passion

Leveraging the EventHandler<T> delegate more effectively

If you are now coding in .Net 2.0/3.0/3.5 and are creating types that expose events. Chances are you have started leveraging the EventHandler<T> delegate that frees you from creating custom delegate signatures for events anymore. If not this post is for you. Let’s say that you want to expose an event that another object could consume. Normally you would follow these steps:

  1. Create a type that inherits from EventArgs if the event is going to propagate event specific data. This step is optional as you may not have any custom data to propagate.
  2. Create a delegate signature for the event. If you are not using a custom EventArgs derivative, then you can get away with just leveraging the EventHandler delegate that already exists in the framework.
  3. Create the type that is going to raise the event and have it declare the event using either implicit or explicit event registration.
  4. Create a method on the type that will raise the event.

In .Net 2.0/3.0/3.5 these steps can now become:

  1. Create a type that inherits from EventArgs if the event is going to propagate event specific data. This step is optional as you may not have any custom data to propagate.
  2. Create the type that is going to raise the event and have it declare the event using either the EventHandler delegate type for an event that does not propagate custom data, or leverage the generic EventHandler<T> delegate to declare an event bound to the specific EventArgs derivative you need to use. Again you can use either implicit or explicit event registration.
  3. Create a method on the type that will raise the event.

This can actually become slightly better. Instead of always creating a class that derives from EventArgs if you need to pass custom data; create a parameter object that encapsulates the information you would want to propagate in the event. This class does not need to inherit from EventArgs. Then create the following utility class:

 

public class EventArgs<T> : EventArgs { private T eventData; public EventArgs(T eventData) { this.eventData = eventData; } public T EventData { get { return eventData; } } }

This means that the 3 steps above can now be changed to:

  1. Create a parameter object that encapsulates any information you want to propagate in the event.. This step is optional as you may not have any custom data to propagate.
  2. Create the type that is going to raise the event and have it declare the event using either the EventHandler delegate type for an event that does not propagate custom data, or leverage the generic EventHandler<T> delegate, with the generic EventArgs<T> class to declare an event bound to the specific parameter object you need to use. Again you can use either implicit or explicit event registration.
  3. Create a method on the type that will raise the event.

 

So if I had a parameter object that looked like this:

public class ReportingPeriod { private DateTime start; private DateTime end; public DateTime Start { get { return start; } } public ReportingPeriod(DateTime start, DateTime end) { this.start = start; this.end = end; } }

I would be able to create a type that raises an event to propagate this data as follows (using implicit registration):

public class ReportTrigger { public event EventHandler<EventArgs<ReportingPeriod>> RunReport; }

Or using explicit registration:

public class ReportTrigger { private EventHandler<EventArgs<ReportingPeriod>> subscribers; public event EventHandler<EventArgs<ReportingPeriod>> RunReport { add { subscribers += value; } remove { subscribers -= value; } } }

Develop With Passion!



Comments

.Net Adventures said:

Very interesting article.From my point of view the class EventArgs<T> can be changed in this way :

class EventArgse<T>:EventArgs where T:new()

   {

       private readonly T eventData;

       // Fields

       public new static readonly EventArgse<T> Empty;

       static EventArgse()

       {

           Empty = new EventArgse<T>();

       }

       private EventArgse()

       {

       }

       public EventArgse(T eventData)

       {

           this.eventData = eventData;

       }

       public T EventData

       {

           get { return eventData; }

       }

   }

As you see I just implemented Null pattern.

# July 11, 2007 3:39 PM

Christopher Steen said:

Announcing the LunchTimerCoder.com Initiative [Via: Chris Pietschmann ] Building a PC, Part I [Via:...

# July 11, 2007 11:14 PM

Insane World said:

Leveraging the EventHandler

# July 13, 2007 3:39 AM

Christopher Steen said:

Link Listing - July 11, 2007

# July 20, 2007 1:52 AM

Mobocracy said:

Can this cross a wcf boundry ? It's my understanding that untyped objects can not cross a wcf boundry.

# July 24, 2007 8:52 AM

bitwisejp said:

@Mobocracy,

I am not sure why you would want to pass an event handler delegate across a wcf boundary.

JP

# August 13, 2007 11:22 AM

Eric Swanson said:

This is fantastic! This starts looking horrible in VB.NET when I used a generic List(Of String). Check out all the parenthesis! Woo hoo!

Dim eventData As New List(Of String)

New EventArgs(Of List(Of String))(eventData)

Public Class EventArgs(Of T)

   Inherits EventArgs

   Private _eventData As T

   Public Sub New(ByVal eventData As T)

       MyBase.New()

       _eventData = eventData

   End Sub

   Public ReadOnly Property EventData() As T

       Get

           Return _eventData

       End Get

   End Property

End Class

I prefer the C# equivalent:

List<string> eventData = new List<string>();

new EventArgs<List<string>>(eventData);

# July 21, 2008 6:29 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors