Click here to Skip to main content
Licence CPOL
First Posted 17 Jun 2008
Views 17,747
Downloads 119
Bookmarked 24 times

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

By | 17 Jun 2008 | Article
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Harvey Saayman

Software Developer
Osiris Trading
South Africa South Africa

Member

Harvey is in the process of completing his BSc in Information Systems Engineering. He finished the 1st two years in less than a year, he is currently doing the last year part time over two years while working full time as a C# developer. The modules he is currently studying covers business & project management.
 
He is getting his degree from Cambridge university UK, all though hes studying at CTi South Africa.
 
He has been a programmer in professional capacity since Jan 2008, but has been exposed to programming from childhood.
 
He currently works for Uniclox Technologies (Pty) Ltd as the lead project developer. Hes a junior on paper, but more senior developers who has seen his work confirmed that his skill level is way beyond that of a junior.
 
Other interests include music, he has been playing guitar for about four years now. He wishes he can afford a proper 7 string ibanez.
 
Harvey's pet of choice isn't of your common 4 legged variety, he prefers reptiles and currently owns a South African brown house snake and an Australian breaded dragon.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralNice work PinmemberDumpsterJuice7:14 18 Jun '08  
GeneralRe: Nice work PinmemberHarveySaayman9:25 18 Jun '08  
GeneralUse of add and remove in events PinmvpPete O'Hanlon5:15 18 Jun '08  
Harvey - a good effort so far, but you may want to talk about the use of add and remove accessors for events. They are overly ignored, but they are useful (especially if you want to make sure that you have balanced += with -= handlers). Here's an example
public event MyEventHandler MyClick
{
  add
  {
    _myClickCount ++;
    _myClick += value;
  }
  remove
  {
    _myClickCount --;
    _myClick -= value;
  }
}
Also, could you put something in about testing the event before triggering it in order to make sure that it is being handled?
protected virtual void OnClick()
{
  if (MyEventHandler)
    MyEventHandler(this, new EventArgs());
}

 
Deja View - the feeling that you've seen this post before.
 

My blog | My articles



GeneralRe: Use of add and remove in events PinmemberHarveySaayman9:37 18 Jun '08  
GeneralRe: Use of add and remove in events PinmvpPete O'Hanlon10:23 18 Jun '08  
GeneralRe: Use of add and remove in events PinmemberHarveySaayman10:45 18 Jun '08  
GeneralRe: Use of add and remove in events PinmemberHarveySaayman10:48 18 Jun '08  
GeneralRe: Use of add and remove in events PinmemberHarveySaayman9:40 18 Jun '08  
GeneralRe: Use of add and remove in events PinmvpPete O'Hanlon10:16 18 Jun '08  

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

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120604.1 | Last Updated 17 Jun 2008
Article Copyright 2008 by Harvey Saayman
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid