C# Tutorial: Understanding C# Events
In this C# event tutorial, I will explain how delegates are the foundation for C# events and show the two primary delegates that Microsoft has given us for creating our own events. I will also show you how to subscribe to your own events and even pass data back to the event handlers.
Every single event in .NET, whether Microsoft created it or if it was created by someone else, is based on a .NET delegate. Delegates are one of the five types of types included with .NET – class, structure, interface, enumeration, and delegate. At its foundation, delegates do two things:
- When created, it points to a method (instance or static) in a container (class or structure). For events, it points to an event hander method.
- It defines exactly the kind of methods that it can point to, including the number and types of parameters and also the return type.
Here is a definition of a simple delegate. It can be declared at the namespace level, meaning it doesn’t need to be nested in a class. The delegate below can only point to a method that accepts two integer parameters and returns an integer. Interestingly, the parameters “a” and “b” are never used directly but they are required to define the delegate.
public delegate int dgPointer(int a, int b);
You can create an instance of the delegate pointing to a method. Then, every time you call the delegate, it calls the method for you. If the method returns a value, the delegate returns it for you. Here’s a complete simple example.
public delegate int dgPointer(int a, int b); class Program { static void Main() { Adder a = new Adder(); dgPointer pAdder = new dgPointer(a.Add); int iAnswer = pAdder(4, 3); Console.WriteLine("iAnswer = {0}", iAnswer); // Returns “iAnswer = 7” } } public class Adder { public int Add(int x, int y) { return x + y; } }
As useless and redundant as the code appears, delegates can be set at run time rather than design time. This adds flexibility to our code. We can assign methods as our app is running based on current variable values. For events, we can dynamically subscribe and unsubscribe to events with event handler methods.
Let’s assume we want to raise an event in the Adder class if the sum of the two numbers in Add() is a multiple of five (5). We can define an event based on the delegate. This event will be used to raise a notification to run event handlers assigned to it.
NOTE: All C# events in .NET are based on delegates.
NOTE: Wherever you want to raise an event, you must also define the event.
NOTE: You must never raise (publish) an event unless at least one object is listening (subscribing) to the event. In other words, the event must not equal null.
NOTE: A Microsoft Best Practice: All events should be defined starting with the word “On”.
public class Adder { public delegate void dgEventRaiser(); public event dgEventRaiser OnMultipleOfFiveReached; public int Add(int x, int y) { int iSum = x + y; if ((iSum % 5 == 0) && (OnMultipleOfFiveReached != null)) { OnMultipleOfFiveReached(); } return iSum; } }
This code only raises the C# event if there is any code subscribing to it. Let’s modify the code by removing the simple delegate and have it subscribe to the event.
class Program { static void Main() { Adder a = new Adder(); a.OnMultipleOfFiveReached += new Adder.dgEventRaiser(a_MultipleOfFiveReached); int iAnswer = a.Add(4, 3); Console.WriteLine("iAnswer = {0}", iAnswer); iAnswer = a.Add(4, 6); Console.WriteLine("iAnswer = {0}", iAnswer); Console.ReadKey(); } static void a_MultipleOfFiveReached() { Console.WriteLine("Multiple of five reached!"); } }
When run, here is the result:
This code creates a new instance of the dgEventRaiser delegate that points to the new method called a_MultipleOfFiveReached. The += operator is used to protect other methods that may have already subscribed to the event.
Microsoft made it easier for us to subscribe to C# events. The long line of code above can be shortened to the following snippet with the same effect.
a.OnMultipleOfFiveReached += a_MultipleOfFiveReached;
This code works fine but the code in the Adder class is more complex than it needs to be. Microsoft has included two (2) primary delegates that we can use when defining events. These delegates are used everywhere in the framework and can be easier to use because of their consistent pattern.
Here are the two built-in delegates:
public delegate void EventHandler(object sender, EventArgs e); public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The first delegate is used simply to raise a notification, an event signifying that something happened. The second delegate allows you to return one or more values to the event handler method. It requires you to create an instance of a class that derives from the EventArgs class.
To modify our code to use the first built-in delegate, we can delete our delegate and change our C# event to use the EventHandler delegate. When we raise the event, we must follow along with the delegate definition and pass in the required parameter values. Note how we pass our current instance of adder for the first parameter (sender) and since we are not passing back any event arguments, we use EventArgs.Empty for “e”.
We also had to change our event handler method to follow the pattern of the delegate with (object sender, EventArgs e).
class Program { static void Main() { Adder a = new Adder(); a.OnMultipleOfFiveReached += a_MultipleOfFiveReached; int iAnswer = a.Add(4, 3); Console.WriteLine("iAnswer = {0}", iAnswer); iAnswer = a.Add(4, 6); Console.WriteLine("iAnswer = {0}", iAnswer); Console.ReadKey(); } static void a_MultipleOfFiveReached(object sender, EventArgs e) { Console.WriteLine("Multiple of five reached!"); } } public class Adder { public event EventHandler OnMultipleOfFiveReached; public int Add(int x, int y) { int iSum = x + y; if ((iSum % 5 == 0) && (OnMultipleOfFiveReached != null)) { OnMultipleOfFiveReached(this, EventArgs.Empty); } return iSum; } }
In order to use the other delegate and pass the grand total back to the event hander method, we first need to define a custom class called MultipleOfFiveEventArgs for passing back a custom value, such as Total. It must inherit from the EventArgs class.
Then we will need to define our event to use the other generic delegate which includes the custom EventArgs type, MultipleOfFiveEventArgs. We must also change how we raise the event. Finally, we change the event handler method to match the delegate. Here is the complete code:
class Program { static void Main() { Adder a = new Adder(); a.OnMultipleOfFiveReached += a_MultipleOfFiveReached; int iAnswer = a.Add(4, 3); Console.WriteLine("iAnswer = {0}", iAnswer); iAnswer = a.Add(4, 6); Console.WriteLine("iAnswer = {0}", iAnswer); Console.ReadKey(); } static void a_MultipleOfFiveReached(object sender, MultipleOfFiveEventArgs e) { Console.WriteLine("Multiple of five reached: ", e.Total); } } public class Adder { public event EventHandler<MultipleOfFiveEventArgs> OnMultipleOfFiveReached; public int Add(int x, int y) { int iSum = x + y; if ((iSum % 5 == 0) && (OnMultipleOfFiveReached != null)) { OnMultipleOfFiveReached(this, new MultipleOfFiveEventArgs(iSum)); } return iSum; } } public class MultipleOfFiveEventArgs : EventArgs { public MultipleOfFiveEventArgs(int iTotal) { Total = iTotal; } public int Total { get; set; } }
I hope this C# events tutorial has been helpful for you in learning delegates and events. Best wishes and happy programming!
I just googled and found this as I’ve not written events in a while and realised I couldn’t quite remember. Sometimes a good simple tutorial can do wonders – this is excellent!
Great. Thanks.
Nice tutorial! This tutorial provides novices a comprehensive concept using Event and Delegates!!
finally got it, many thanks for your clear article, if you wrote a book on c# i would certainly buy it
Thanks
Excellent, I actually comprehend them now!
The reason so many developers get confused about event handling is because nobody has explained it so thoroughly and clearly as you. I’ve struggle for the last few days reading other tutorials and yours is the only one I understand. Thanks for taking the time to write this up.
Awesome explanation. Thanks so much
Very very helpful!
Nice article. I would only say, in the final version of the code You could have removed the original delegate definition of dgPointer and written main as follows:
static void Main()
{
Adder a = new Adder();
a.OnMultipleOfFiveReached += a_MultipleOfFiveReached;
int iAnswer = a.Add(4, 3);
Console.WriteLine(“iAnswer = {0}”, iAnswer);
iAnswer = a.Add(4, 6);
Console.WriteLine(“iAnswer = {0}”, iAnswer);
Console.ReadKey();
}
because Dot Net already created delegate of Type EventHandler
thank you for the explanation!
Finally understood thanks to your article. Thanks!
highly appreciated that you can actually translate codes into human language. finally start to get a grip after watching so many tutorials. thanks.
event EventHandler FileOpenClick;
butOpenFile. Click += ButOpenFile_Click;
private void ButOpenFile_Click(object sender, EventArgs e) //I am not
{ //understand
if (FileOpenClick != null) FileOpenClick(this, EventArgs.Empty); //this part
} //of the code
FileOpenClick += View_FileOpenClick;
private void View_FileOpenClick(object sender, EventArgs e)
{
//Some code
}
Guys! Please help me! I have this piece of the code and I am not understand why ButOpenFile_Click has another event check?
ty
Very helpful!.. found lots of discussions addressing this but this one was the most clear one!
this tutorial gave clear understanding about delegate and event.
with this, I learned really useful knowledge.
thanks for people shared this tutorial.
That is awesome! Never seen such great explanation of quite difficult topic. From basics to advance!