Event, Custom Event and Generic Event in .NET

2012-05-30


We often need to implement events in our own class. About how to implement events, Microsoft provides tutorials such as this one.

About the concepts of Event and Delegate, please read Microsoft site here.

I. Traditional Method:

Microsoft provides tutorials seems still in .NET 1.1 way even the web page is showing for .NET Framework 4, this is the traditional way to implement an event in custom class:

For event-specific data:

1: If for an event with event-specific data:

Create custom EventArgs, just like Microsoft’s sample:

public class MyEventArgs : EventArgs
{
    private string msg;

    public MyEventArgs( string messageData ) {
        msg = messageData;
    }
    public string Message { 
        get { return msg; } 
        set { msg = value; }
    }
}

2: like 1, this case is still if for an event with event-specific data:

Declare a delegate for the event, use the name like EventNameEventHandler;

public delegate void MyEventHandler(object sender, MyEventArgs e);

3: Define a public event in our class. Set the type of the event member to the event delegate type.

 public class MyClassIncludesDefinedEvent
{
    public event MyEventHandler MyEvent;
    ...
}

4: Define a protected method in our class that raises the event:

public class MyClassIncludesDefinedEvent
{
    public event MyEventHandler MyEvent;

    protected virtual void OnMyEvent(MyEventArgs e)
    {
      if (MyEvent != null) 
          MyEvent(this, e); 
    }
}

5: Since our raising event method is protected, we’d better define another method in the same class to "launch" our OnMyEvent, also, we need to initial our MyEventArgs:

public class MyClassIncludesDefinedEvent
{
    public event MyEventHandler MyEvent;

    protected virtual void OnMyEvent(MyEventArgs e)
    {
      if (MyEvent != null) 
          MyEvent(this, e); 
    }

    public void CallEvent(string newMsg)
    {
       OnMyEvent(new MyEventArgs(newMsg));
    }
}

6: Then, we can consumer our custom event just like below sample:

private void Form1_Load(object sender, EventArgs e)
{
    MyClassIncludeDefinedEvent myEventClass = new MyClassIncludeDefinedEvent();            

    myEventClass.MyEvent += new MyEventHandler(myEventClass_MyEvent);
    myEventClass.CallEvent("My Custome Event Test.");            
}

void myEventClass_MyEvent(object sender, MyEventArgs e)
{
    MessageBox.Show(e.Message);
}

When we run above sample, we can get the correct result successfully:

image

For Non-event-specific data:

If we do not need event-specific data, it means we do not need a custom EventArgs (above samle: MyEventArgs), we do not need to define a custom delegate but just use .NET’s pre defined  EventHandler.

Then we can skip the above step 1 and step 2, In Step 3, we use like below (for testing, we create a new class named MyClassIncludesDefinedEvent2):

 public class MyClassIncludesDefinedEvent2
{
    public EventHandler MyEvent;
    ...
 }

The next we put other methods like the following:

(Note: now the EventArgs changed to the default EventArgs too, which is defined by .NET too)

public class MyClassIncludesDefinedEvent2
{
    public event MyEventHandler MyEvent;

    protected virtual void OnMyEvent(EventArgs e)
    {
      if (MyEvent != null) 
          MyEvent(this, e); 
    }

    public void CallEvent()
    {
       OnMyEvent(new EventArgs());
    }
}

Then we can consumer our event using the following code:

private void Form1_Load(object sender, EventArgs e)
{
    MyClassIncludeDefinedEvent2 myEventClass2 = new MyClassIncludeDefinedEvent2();
    myEventClass2.MyEvent += new EventHandler(myEventClass2_MyEvent);
    myEventClass2.CallEvent();
}

void myEventClass2_MyEvent(object sender, EventArgs e)
{
    MessageBox.Show("This is Non-specific data event test.");
}

We also get event launched result:

image

II. New Method – Generic Event Method (Since .NET 2.0 )

From previous sample, we can see .NET provides a EventHandler which let us ignore delegate define, actually, .NET defined delegate for us automatically without need us define. But, for the event with specific data (generated data), we have to define delegate handler for each time. just like this:

public delegate void MyEventHandler(object sender, MyEventArgs e);

Most of cases, when we define delegate handler, only the second parameter is different, So why don’t .NET provide another style EventHandler to let us skip defining the delegate too for those specific data events ?

Yes, Since .NET 2.0, Microsoft provided the Generic EventHandler, which let us reduce some works.

Let’s go back to the sample 1 above (For event-specific data):

1: Step 1 keeps the same: define MyEventArgs

2: We do not need to define a delegate handler this time, but just use Generic EventHandler;

3: We create a new class to replace the first class MyClassIncludesDefinedEvent, The new class named MyGenericEventClass, its full content is the following:

public class MyGenericEventClass
{
    public event EventHandler MyEvent;

    protected virtual void OnMyEvent(MyEventArgs e)
    {
        // Copy to a temporary variable to be thread-safe.
        EventHandler tempEvent = MyEvent;
        if (tempEvent != null)
            tempEvent(this, e);
    }

    public void CallEvent(string newMsg)
    {
        OnMyEvent(new MyEventArgs(newMsg));
    }
}

Actually the last two methods in above class can be merged to the single method, just like the following:

public class MyGenericEventClass
{
    public event EventHandler MyEvent;

    public void CallEvent(string newMsg)
    {
        // Copy to a temporary variable to be thread-safe.
        EventHandler tempEvent = MyEvent;
        if (tempEvent != null)
            tempEvent(this, new MyEventArgs(newMsg));	
    }
}

Then we can consume the generic event like the following:

private void Form1_Load(object sender, EventArgs e)
{
    MyGenericEventClass  myGenericEventClass = new MyGenericEventClass();

    myGenericEventClass.MyEvent += new EventHandler(myGenericEventClass_MyEvent);
    myGenericEventClass.CallEvent("My Generic Event Test.");
}

void myGenericEventClass_MyEvent(object sender, MyEventArgs e)
{
    MessageBox.Show(e.Message); 
}

Also, we can get correct result:

image