Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Delegates, Events, Event Arguments, and How They Fit Together

0.00/5 (No votes)
17 Jun 2008 1  
Delegates, events, event arguments, and how they fit together.

delegate___events2.JPG

Introduction

For me, delegates and events used to be a frightening phenomenon, and I used to avoid writing custom events as far as possible. But, that only worked out until I had to write some pretty complicated custom controls that had to be able to let each other know what was happening.

So, I set out too understand them before trying to use them. After searching the net, I couldn’t find any article that explained them in such a way that even a beginner could understand it. Just little bits and pieces were not making sense to me, because in my opinion, there was far too much unnecessary code in between most of the examples to grasp the basic concept of what was needed to put an event together.

It took me quite a while to make sense of what was happening in the code examples and which parts were event related, but armed with a compiler and determination, I found the answers I was looking for.

Background

First of all, this article is intended to be an online reference for myself, what I’ve learnt though trial, error, and other developers in the forums. If someone else finds this information useful, I’m glad that I could have been of service, and hope I’ve saved you hours of research.

To grasp the concepts, I suggest you have some basic knowledge of the following subjects:

  • Inheritance
  • Classes and constructors
  • Properties
  • How objects are passed to other objects

A Bird's Eye View

The picture above illustrates how the pieces that form an event will typically fit together. I’ll explain them one by one from the inside out.

Delving Deeper

The Event Object

This is the object associated with an event, this is what you will call to trigger an event. You’ll also use it to “register” another object to be able to handle the event.

Syntax:

[Access Modifier] event [Delegate] yourEventName;

Example:

public event someDelegate myEvent;

Note:

Try to think that an event is of type delegate.

The Delegate Object

This is the signature of your event. An event will often need to have arguments, and this is where you will specify the objects that will be passed to the event when it's triggered, and to the objects that “registered” to handle the event.

Syntax:

[Access Modifier] delegate [Return Type] 
     yourDelegateName([Objects That Will Be Passed To It])

Example:

public delegate void myDelegate(object sender, EventArgs e)

Note:

I’ve not yet needed a delegate to return a value, so I’m not sure in what kind of a situation it would be needed, but I’m sure it will be discussed in the forum underneath this article.

Event Arguments Object

This is a class like any other, with private variables and public properties, or just public variables, whichever way you need it. It inherits from System.EventArgs. Think of this class as a box that holds all the variables that you’d like your event handler to know about the event.

public class myCustomEventArgs : EventArgs
{
    public myCustomEventArgs(bool aBooleanVariable)
    {
        this.MyBooleanVariable = aBooleanVariable;
    }

    private bool myBooleanVariable;
    public bool MyBooleanVariable
    {
        Get
        {
            return myBooleanVariable; 
        }
        Set
        {
            myBooleanVariable = value;
        }
    }
}

This is a class like any other with private variables and public properties or just public variables, which ever way you need it. It also inherits from System.EventArgs. Think of this class as a box that holds all the variables that you’d like your event handler to know about the event.

The Triggering Object

This is the object that will trigger your event, and also the object that contains the event and delegate objects. This would typically (in my experience) be a custom control. Think about a simple button, the event and delegate objects will be inside the button's code. And, when the physical event of a user moving the mouse pointer to the control’s area and clicking the left mouse button takes place, the programmatic event will be triggered so that it can be handled.

In this button example, the event will be handled twice, internally (in the button's code itself) and externally (in the form that contains this button).

The internal event handler will tell the button's painting methods to paint the button in such a way that it seems to be going into the screen, like an actual button would look after pressing it. The external event handler is what the programmer who uses the button control will use to change the color of the form, for example.

To trigger the event, we simply call it like so:

myEvent(this, new myCustomEventArgs(false));

Note:

If you don’t need any special argument objects, you can just replace myCustomEventArgs() with EventArgs(), a class already in the .NET framework.

The Catching Object

This is the object or objects that will handle the event once it is triggered. But, before an object can handle an event, it must “register” or add a listener for it. To do that, we’ll do the following:

myEvent += new myEvent(methodToExecuteOnceEventIsTriggered);

Similarly, if we no longer want to know if the event has been triggered, we do the following:

myEvent -= new myEvent(methodToExecuteOnceEventIsTriggered);

Once that is done, we have to write a handler for the event. Note that the objects passed to the methods must be the same as specified in the delegate.

public void ButtonsHaveBeenPushed(object sender, myCustomEventArgs e)
{
    //some code to execute once the event has fired
}

Explaining the Sample Project

The sample project was written in Visual Studio 2008. It consists of a parent form FrmParent and a child form FrmChild.

In the constructor of the parent, an instance of the child form is created…

//create an instance of the child form
FrmChild frmChild = new FrmChild();
//display the child form
frmChild.Show(); 

The Custom Event Arguments

Below the FrmParent class is another class, myCustomEventArgs, that inherits from EventArgs. This is the argument “box” that we will pass to every object that registered to handle the event. It consists of a constructor and three variables, a string, an int, and a bool.

Inside of the constructor, we are assigning the variables passed to the myCustomEventArgs class on its creation to its public variables. We do this so that the event handlers can access those values later.

public class myCustomEventArgs : EventArgs
{
    public myCustomEventArgs(string myString, bool myBool, int myInt)
    {
        _string = myString;
        _bool = myBool;
        _int = myInt;
    }

    public string _string;
    public bool _bool;
    public int _int;
}

The Delegate

The delegate object is declared inside the FrmParent class, and looks like so…

public delegate void myDelegate(object sender, myCustomEventArgs e);

Remember that the delegate is the signature of the event; we want our event to pass our custom event arguments to the handlers, so here is where we specify that.

The Event

The event object is also declared inside the FrmParent class, because this is where we are going to fire the event. The declaration is as follows…

public static event myDelegate myEvent;

Note that in the sample project, the event is static, the reason for this is that the child wants access to the event. The static keyword means that only one instance of the event may exist at any given time during the execution of the program. It also means that we do not have to instantiate FrmParent to be able to use it.

Firing the Event

The delegate and event objects were created in FrmParent, and this is where we will fire our event. To fire it, I added a button to the form, and in its OnClick handler, the following code is executed:

myEvent(btnTrigger, new myCustomEventArgs(textBox.Text, 
        checkBox.Checked, (int)numericUpDown.Value));

Here, we are calling the event, myEvent. In its brackets, we need to specify the arguments. First off, we need to tell the handler who fired the event, so btnTrigger is added. Next, we create a new instance of the myCustomEventArgs class, and add the values of the text box, numeric up down, and the check box on FrmParent to it.

Handling the Event

Before we can handle the event, we must register for it. In the sample project, we handle the event twice, in FrmParent and in FrmChild.

To register it in FrmParent, we do the following in the constructor…

myEvent += new myDelegate(FrmParent_myEvent);

To register it in FrmChildwe, do the following in its constructor…

FrmParent.myEvent += new FrmParent.myDelegate(FrmParent_myEvent);

Note that I used the object name FrmParent, and not an instance of it while specifying the event. We can do this because of the static keyword; remember our event was declared as static?

Next, we need to write the methods to execute once the event has fired. In FrmMain, we’ll just display a message box to show that the event has fired.

void FrmParent_myEvent(object sender, myCustomEventArgs e)
{
    MessageBox.Show("The Event Was Triggered!");
}

In FrmChild, we are going to display the values of our custom event arguments (those that came from FrmParent) in text boxes on FrmChild.

void FrmParent_myEvent(object sender, myCustomEventArgs e)
{
    //assign the values of the event arguments to the text boxes
    txtString.Text = e._string;
    txtInteger.Text = e._int.ToString();
    txtBoolean.Text = e._bool.ToString();
}

What Did We Just Do?

What happens now is once values have been entered into the controls on FrmParent and the event gets fired, those values are assigned to text boxes on FrmChild as a response to the event that occurred.

Points of Interest

Events are very useful, and can be used to achieve anything from passing data between forms, to let the parent of a custom control know that its data is validated and correct.

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