Events and event handling in C#

Introduction

An event is a mechanism via which a class can notify its clients when something happens. For example when you click a button, a button-click-event notification is sent to the window hosting the button. Event s are declared using delegates. So if you don't know what a delegate is, you may go and read my article on delegates first. The first time you go through this article you might find it confusing, don't worry about that. Just try out the sample program and go through the sample source, line by line. Maybe, you can read the article once more after that. Once you get the hang of it, things will seem simple. By the way this article is intended for beginners and is not meant for advanced level programmers.

The Program

I include the full program below. It's not commented but later down this article, I have taken the program part by part and explained each part. I have also included the output you'll get on running the program.

using System;

 

public delegate void DivBySevenHandler(object o, DivBySevenEvent Args e);

 

public class DivBySevenEvent Args : Event Args

{

    public readonly int TheNumber;

   

    public DivBySevenEvent Args(int num)

    {

        TheNumber = num;

    }   

   

}

 

public class DivBySevenListener

{

    public void ShowOnScreen(object o, DivBySevenEvent Args e)

    {

        Console.WriteLine(

            "divisible by seven event raised!!! the guilty party is {0}",

            e.TheNumber);

    }   

}

 

public class BusterBoy

{

    public static event DivBySevenHandler Event Seven;

   

    public static void Main()

    {

         DivBySevenListener dbsl = new DivBySevenListener();

        Event Seven += new DivBySevenHandler(dbsl.ShowOnScreen);

        GenNumbers();

    }

   

    public static void OnEvent Seven(DivBySevenEvent Args e)

    {

        if(Event Seven!=null)

             Event Seven(new object(),e);

    }   

   

    public static void GenNumbers()

    {

        for(int i=0;i<99;i++)

        {

            if(i%7==0)

            {

                DivBySevenEvent Args e1 = new DivBySevenEvent Args(i);

                OnEvent Seven(e1);

            }

        }       

    }

       

}

//Output

 

F:/c#/event s>1

divisible by seven event raised!!! the guilty party is 0

divisible by seven event raised!!! the guilty party is 7

divisible by seven event raised!!! the guilty party is 14

divisible by seven event raised!!! the guilty party is 21

divisible by seven event raised!!! the guilty party is 28

divisible by seven event raised!!! the guilty party is 35

divisible by seven event raised!!! the guilty party is 42

divisible by seven event raised!!! the guilty party is 49

divisible by seven event raised!!! the guilty party is 56

divisible by seven event raised!!! the guilty party is 63

divisible by seven event raised!!! the guilty party is 70

divisible by seven event raised!!! the guilty party is 77

divisible by seven event raised!!! the guilty party is 84

divisible by seven event raised!!! the guilty party is 91

divisible by seven event raised!!! the guilty party is 98

 

F:/c#/event s>

Explanation

Okay. I presume you have taken a look at the above program and I bet you have all guessed it's purpose. We generate some numbers and every time we generate a number that is divisible by 7 we raise an event . The event handler will print out a message saying that the event was raised and it also prints out the number responsible for raising the event . I guess some of you are frowning and saying that's a stupid reason to raise an event . I know, I know alright. The program is not intended to be used for any useful purpose. It's only an attempt to make event s comprehensible. I hope it served it's role out. :-)

Okay, so the first thing we did was to declare a delegate.

public delegate void DivBySevenHandler(object o, DivBySevenEvent Args e);

The delegate defines the parameters sent to the event handlers. Thus any class that wants to handle this event must have a handler method which has the same return type and argument list as this delegate. Here as you can see, the first parameter is an object. In real-world cases event handlers are normally passed a reference to the sending object. I am not doing that in this program. I am simply passing a new object() to the event handler. Normally you can pass a this reference. The second parameter is a System.Event Args derived class. System.Event Args is the base class for encapsulating event related data. We use it to send information regarding the event to its handler.

Now, we define the Event Args derived class as follows:-

public class DivBySevenEvent Args : Event Args

{

    public readonly int TheNumber;

       

    public DivBySevenEvent Args(int num)

    {

        TheNumber = num;

    }         

}

As you can see, it has a public read-only member which is used to store our generated number that is divisible by 7. Normally you should use properties but for the sake of simplicity I am using a public member variable.

Now we define our listener class which is the class that needs to be notified of the event .

public class DivBySevenListener

{

    public void ShowOnScreen(object o, DivBySevenEvent Args e)

    {

        Console.WriteLine(

            "divisible by seven event raised!!! the guilty party is {0}",

            e.TheNumber);

    }  

}

As you can see, it has a function ShowOnScreen that matches the delegate type we defined on top. You can see how we use the passed DivBySevenEvent Args object to print out the number that is divisible by seven.

Now, let's examine our Main() containing class. We first declare the event as follows:-

public static event DivBySevenHandler Event Seven;

An event is declared like a delegate type variable, except that the keyword event precedes the event declaration.

Now let's take a look at the function that invokes the event and thus notifies all clients.

public static void OnEvent Seven(DivBySevenEvent Args e)

{

    if(Event Seven!=null)

        Event Seven(new object(),e);

}

Event Seven will be null if no client has hooked up a delegate to the event . We need to check if it is null unless you want to see an exception raised. If it's not null we invoke the event , passing a dummy object [I have explained above why I passed a dummy] and the passed DivBySevenEvent Args object. And all clients get notified.

Let's look at the function GenNumbers() now :-

public static void GenNumbers()

{

    for (int i=0;i<99;i++)

    {

        if(i%7==0)

        {

            DivBySevenEvent Args e1 = new DivBySevenEvent Args(i);

            OnEvent Seven(e1);

        }

    }         

}

We use the for() loop to iterate from 0 to 98, and in each case we check for divisibility by 7. If we find that the number is divisible by 7 we create a DivBySevenEvent Args object passing the culprit number to the constructor. Now we call the OnEvent Seven() function passing the DivBySevenEvent Args object we just created. 

Now lets go through Main()

public static void Main()

{

    DivBySevenListener dbsl = new DivBySevenListener();

    Event Seven += new DivBySevenHandler(dbsl.ShowOnScreen);

    GenNumbers();

}

We first create a DivBySevenListener object. Then using the += operator we compose a delegate into the event field. Even though I haven't used the -= operator, you can use it to remove a delegate from an event . Once we've done all that we call GenNumbers() . Thus we've set everything up nice and proper. GenNumbers() will do its job like a faithful puppy by generating numbers from 0 to 98 just as we expected it to. Every time it generates a number divisible by 7 it will raise the event .

Conclusion

Well you have just seen how you can create event s and event handlers. You must remember that event s can be invoked only from the class that declared them. This causes problems with regard to inheritance. Thus if you have a class with an event you'd better make your OnWhateverEvent () function protected so that the derived classed can call it. Better still, make it virtual too, so they can override it in their class.

作者:Angelo Lee
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文地址:https://www.cnblogs.com/yefengmeander/p/2888047.html