
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)
{
}
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…
FrmChild frmChild = new FrmChild();
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)
{
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.