Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C#
Article

Events in C#

Rate me:
Please Sign up or sign in to vote.
2.75/5 (23 votes)
9 May 20078 min read 62.2K   37   6
A tutorial on events in C#

Introduction

Events is one of the fantastic features in C# after delegates. Events is a mechanism of generating notification. In C#, objects of a class can send events to objects of other classes and Objects of classes that receive events can handle events the way they want. In other words, we have objects that are instances of classes. Objects can generate events. Objects can receive and process events.

To explain the concept of events we will make use of simple examples. Our First example will consist of two classes: Event Generator and Event Receiver. Here we will show you how the event generator class generates an event and how the event receiver class receives and processes the event. Our second example will consists of three classes: one Event Generator class, and two Event Receiver classes. Here we will show you how the event generator class generates an event and how the event receiving classes receives and processes the event. In our last example we will present you with a real-life scenario of students seeking admission to college and how to simulate this real-life scenario using classes and events.

Example1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
    Evt += new LinkToEventHandler(c1_o1.Client1EventHandler);
    DoSomething();    
  }  

  public static void DoSomething()
  {
    System.Console.WriteLine("Something Happened! We need to send an event.");
    SendEvent();
  }

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

Output

Something Happened! We need to send an event.
EventHandler Called for object Object1 of Client1 class

The above program compiles and runs successfully to produce a desired output. Cool! Now let's have a look at the above program. Looks like something complex stuff! But believe me, it's not. Let me explain the program.

The above program consists of two classes:

  1. EventGeneratorClass: This is the class that is responsible for generating event.
  2. Client1: This is the class that is responsible for receiving and handling the event.

Cool! So we have two types of classes, an event generating class and an event receiving class. Simple isn't it?

Let's develop the program step by step so that it is easy for you to comprehend.

P1.cs

C#
class Client1
{ 

}

class EventGeneratorClass
{

}

Now let's proceed. Lets focus our attention to the Client1 class and then to the EventGenerator class. OK! So our Client1 class has a data member string variable called name. So our program would look like this:

P1.cs

C#
class Client1
{ 
  string name;
}

class EventGeneratorClass
{

}

Now we want to initialize the variable name! So Client1 class has a one argument constructor. This constructor initializes the data member string variable name. Thus whenever we create an object of class Client1 we pass the name of the object as a string to the class constructor. The program will now look like this.

P1.cs

C#
class Client1
{ 
  string name;

  public Client1(string nameArg)
  {
     name = nameArg;
  }
}

class EventGeneratorClass
{

}

OK! Remember, we had mentioned that the Client1 class is an event receiving and event handling class. That's because Client1 class has an event Handling function. So let's add the event handling function to the Client1 class in the above program.

P1.cs

C#
class Client1
{ 
  string name;

  public Client1(string nameArg)
  {
     name = nameArg;
  }

  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{

}

The name of the event handling function is Client1EventHandler(). This is a simple function that accepts nothing and returns nothing. It merely prints a message that indicates the name of the object that has received and is processing the event. Every time the object of class Client1 receives an event, its Client1EventHandler() function has to get called because that is the reason we have written it.

Cool! We are done with the explanation of the Client1 class. Now let's focus on the explaination and creation of the EventGeneratorClass for the above program itself. Let's have an entrypoint Main() function for our event generator class. Our enhanced class and hence the program will look like this.

P1.cs

C#
class Client1
{ 
  string name;

  public Client1(string nameArg)
  {
     name = nameArg;
  }

  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static void Main()
  {

  }
}

The job of event generator class is to send events to its clients i.e. objects of Client1 class. So let's create an object of class Client1 inside Main(). The enhanced program will look like this.

P1.cs

C#
class Client1
{ 
  string name;

  public Client1(string nameArg)
  {
     name = nameArg;
  }

  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static void Main()
  {
     Client1 c1_o1 = new Client1("Object c1_o1 of Client1 class");
  }
}

Here we are creating object c1_o1 of class Client1 and while doing so we are passing the name of the object to the constructor. So far so cool!

Now the time has arrived for understanding the Events. So far we have successfully created two classes:

  1. EventGeneratorClass: This is the class that is responsible for generating events.
  2. Client1: This is the class that is responsible for receiving and handling the event.

The EventGeneratorClass will throw events in the open space. The Client1 class will catch the events. The link between the events generated by the EventGeneratorClass and the event handler belonging to the client class is established by the delegate that has the signature of the event handler. So let's define a delegate by the name LinkToEventHandler(). The program would now look like this.

P1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;

  public Client1(string nameArg)
  {
     name = nameArg;
  }

  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static void Main()
  {
     Client1 c1_o1 = new Client1("Object c1_o1 of Client1 class");
  }
}

Now since EventGeneratorClass is going to generate an event, we need to declare an event in this class. We do so and the program looks like this.

P1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
  }  
}

Now EventGeneratorClass has declared an event Evt. Thus, EventGeneratorClass can send an event Evt. So let's have a function by the name SendEvent() as a member of the class EventGenerator. The program will look like this.

P1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
  }  

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

The SendEvent() function checks if Evt is not null and if it's not null sends an event by saying Evt(). Ok! So the event is being sent. But in order for Client1 class's objects to receive the event sent by EventGeneratorClass, the object's event Handler should be regestired with the event Evt of the EventGeneratorClass. Thus, the following code registers the event handler of c1_o1 with the event Evt of EventGeneratorClass.

P1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
    EventForClients += new EventHandler(c1_o1.Client1EventHandler);
  }  

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

OK! Now what remains is the final step! And that is invoking the SendEvent() function. We define a function called DoSomething from which we invoke the SendEvent() function. The DoSomething function is invoked from Main(). The enhanced program looks like this.

P1.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
    Evt += new LinkToEventHandler(c1_o1.Client1EventHandler);
    DoSomething();    
  }  

  public static void DoSomething()
  {
    System.Console.WriteLine("Something Happened! We need to send an event.");
    SendEvent();
  }

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

Output

Something Happened! We need to send an event.
EventHandler Called for object Object1 of Client1 class

Bingo! We are done with the explanation. The above program compiles and runs successfully to give the desired output. The execution begins from the entry point function Main(). Object c1_o1 of class Client1 is created. The event handler of c1_o1 is the function named c1_o1.Client1EventHandler(). The event handler of c1_o1 is registered with the EventGenerator class's event Evt. The DoSomething function is invoked. Inside the DoSomething() function, something happens and the SendEvent() function is invoked to send an event. Inside the SendEvent() function, a check is made to see if any event handler is registered with the EventGenerator class's event Evt i.e. a check is made to see if Evt is not equal to null. If the event handler is resgistered with the EventGenerator class's event Evt i.e. if Evt is not equal to null then the event is generated by the statement Evt(). This event is trapped by the event handler of object c1_o1 because the event handler of c1_o1 object was registered with the EventGenerator class's event Evt. Now the event handler of the c1_o1 object is executed i.e. c1_o1.Client1EventHandler() is executed. The c1_o1.Client1EventHandler() prints the EventHandler called for object c1_obj. Wasn't that easy!

Take the following program where we have multiple instances of the same Client1 class receiving and processing the events generated by the EventGeneratorClass.

P2.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
    Client1 c1_o2 = new Client1("Object2 of Client1 class");
    Client1 c1_o3 = new Client1("Object3 of Client1 class");
    Evt += new LinkToEventHandler(c1_o1.Client1EventHandler);
    Evt += new LinkToEventHandler(c1_o2.Client1EventHandler);
    Evt += new LinkToEventHandler(c1_o3.Client1EventHandler);
    DoSomething();    
  }  

  public static void DoSomething()
  {
    System.Console.WriteLine("Something Happened! We need to send an event.");
    SendEvent();
  }

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

Output

Something Happened! We need to send an event.
EventHandler Called for object Object1 of Client1 class 
EventHandler Called for object Object2 of Client1 class 
EventHandler Called for object Object3 of Client1 class

The above program compiles and runs successfully to give the desired output. The event handlers are called for respective objects because they were registered to receive the events generated by the EventGeneratorClass.

We can also have multiple instances of the multiple Client classes receiving and processing the events generated by the EventGeneratorClass. This is our second example as proposed in the begining of the chapter.

Example2.cs

C#
public delegate void LinkToEventHandler();

class Client1
{ 
  string name;
  public Client1(string nameArg)
  {
     name = nameArg;
  }
  public void Client1EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class Client2
{ 
  string name;
  public Client2(string nameArg)
  {
     name = nameArg;
  }
  public void Client2EventHandler()
  {
    System.Console.WriteLine("EventHandler Called for object {0}", name);
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler Evt;
  
  public static void Main()
  {
    Client1 c1_o1 = new Client1("Object1 of Client1 class");
    Client1 c1_o2 = new Client1("Object2 of Client1 class");
    Client1 c1_o3 = new Client1("Object3 of Client1 class");

    Client1 c2_o1 = new Client1("Object1 of Client2 class");
    Client1 c2_o2 = new Client1("Object2 of Client2 class");
    Client1 c2_o3 = new Client1("Object3 of Client2 class");

    Evt += new LinkToEventHandler(c1_o1.Client1EventHandler);
    Evt += new LinkToEventHandler(c1_o2.Client1EventHandler);
    Evt += new LinkToEventHandler(c1_o3.Client1EventHandler);

    Evt += new LinkToEventHandler(c2_o1.Client2EventHandler);
    Evt += new LinkToEventHandler(c2_o2.Client2EventHandler);
    Evt += new LinkToEventHandler(c2_o3.Client2EventHandler);

    DoSomething();    
  }  

  public static void DoSomething()
  {
    System.Console.WriteLine("Something Happened! We need to send an event.");
    SendEvent();
  }

  public static void SendEvent()
  {
    if (Evt != null)
    {
       Evt();
    }
  }
}

Output

Something Happened! We need to send an event.
EventHandler Called for object Object1 of Client1 class 
EventHandler Called for object Object2 of Client1 class 
EventHandler Called for object Object3 of Client1 class 
EventHandler Called for object Object1 of Client2 class 
EventHandler Called for object Object2 of Client2 class 
EventHandler Called for object Object3 of Client2 class

The above program compiles and runs successfully to give the desired output. The event handlers are called for respective objects because they were registered to receive the events generated by the EventGeneratorClass. In the above program in addition to Client1 class' objects we also have Client2 class' objects that register to receive the events generated by the EventGeneratorClass and are justified by the output of the above program.

Now it's time to present you the last example which shows how to simulate a real life scenario of students seeking admission to college using classes and events. So let's start with a problem statement.

Tom, Dick and Harry are three male students. Shaka, Laka and Baby are three female students. They are seeking admission to a college named KC College. The cut off percentage is 90. This means only students who get more than 90% will be notified that they have got admission. The rest of them will be notified that they have not been admitted. On the students part, if they get notified that they haven't got the admission, then thay will apply to some other college. Whereas if they do get notified that they have got the admission, then they will pay the fees.

Now let's simulate the above problem using classes and events. Let's have two classes MaleStudent and FemaleStudent. Thus Tom, Dick and Harry will be the objects of MaleStudent class. Shaka, Laka and Baby will be objects of the FemaleStudent Class. Let's have a class called KC_College to represent the KC College. KC College will generate two types of events. It will generate the first type of event when the students are granted the admission and the second type of event when the students are not granted admissions. Each MaleStudent and FemaleStudent class will have an event handler to trap the events generated by the KC college. Let the event Handler be MyNextActionItem(). The entire program is modelled on Example2.cs. The final program would look like this.

example3.cs

C#
public delegate void LinkToEventHandler(int i);

class MaleStudent
{ 
  string name;
  int Marks;

  public MaleStudent(string nameArg, int marks)
  {
     name = nameArg;
     Marks = marks;
  }
  public void MyActionItem(int i)
  {
    if (i == 1)
       System.Console.WriteLine("{0} Got Admission. He must pay fees", name);
    else
       System.Console.WriteLine(
         "{0} did not Get Admission. He must lookout for other college", name);
  }
  public int GetMarks()
  {
     return Marks;
  } 
}

class FemaleStudent
{ 
  string name;
  int Marks;
  
  public FemaleStudent(string nameArg, int marks)
  {
     name = nameArg;
     Marks = marks;
  }
  public void MyActionItem(int i)
  {
    if (i == 1)
       System.Console.WriteLine("{0} got Admission. He must pay fees", name);
    else
       System.Console.WriteLine(
         "{0} did not Get Admission. He must lookout for other college", name);

  }
  public int GetMarks()
  {
     return Marks;
  }
}

class EventGeneratorClass
{
  public static event LinkToEventHandler AdmissionDeniedEvt;
  public static event LinkToEventHandler AdmissionGrantedEvt;

  public static void Main()
  {
    MaleStudent Tom   = new MaleStudent ("Tom",   95);
    MaleStudent Dick  = new MaleStudent ("Dick",  89);
    MaleStudent Harry = new MaleStudent ("Harry", 91);

    FemaleStudent Shaka = new FemaleStudent("Shaka", 92);
    FemaleStudent Laka  = new FemaleStudent("Laka",  88);
    FemaleStudent Baby  = new FemaleStudent("Baby",  91);

    if (Tom.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Tom.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Tom.MyActionItem);

    if (Dick.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Dick.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Dick.MyActionItem);

    if (Harry.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Harry.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Harry.MyActionItem);

    if (Shaka.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Shaka.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Shaka.MyActionItem);

    if (Laka.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Laka.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Laka.MyActionItem);

    if (Baby.GetMarks() >= 90)
       AdmissionGrantedEvt += new LinkToEventHandler(Baby.MyActionItem);
    else
       AdmissionDeniedEvt += new LinkToEventHandler(Baby.MyActionItem);

    SendEvent();  
  }

  public static void SendEvent()
  {
    if (AdmissionGrantedEvt != null)
    {
       AdmissionGrantedEvt(1);
    }

    if (AdmissionDeniedEvt != null)
    {
       AdmissionDeniedEvt(0);
    }
  }
}

Output

Tom Got Admission. He must pay fees
Harry Got Admission. He must pay fees
Shaka got Admission. He must pay fees
Baby got Admission. He must pay fees
Dick did not Get Admission. He must lookout for other college
Laka did not Get Admission. He must lookout for other college

The above program compiles and runs successfully to produce the desired output.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
India India
I am a Software engineer with around 7+ years of experience. Most of my experience is in Storage technology.

Comments and Discussions

 
SuggestionExample2.cs Pin
Member 1301717917-Oct-20 8:21
Member 1301717917-Oct-20 8:21 
GeneralMy vote of 2 Pin
GerhardV2.05-Mar-09 19:22
GerhardV2.05-Mar-09 19:22 
GeneralI hate to be squeamish in languages i don't understand Pin
T.Rankill18-Nov-07 15:16
T.Rankill18-Nov-07 15:16 
GeneralRe: I hate to be squeamish in languages i don't understand Pin
Chetan Kudalkar19-Nov-07 3:22
Chetan Kudalkar19-Nov-07 3:22 
GeneralThank You! Pin
George Boyd Ratcliff7-Aug-07 1:03
George Boyd Ratcliff7-Aug-07 1:03 
GeneralNice job Pin
miies9-May-07 22:06
miies9-May-07 22:06 

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

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