.NET Development Foundation/Using events
System types and collections: Using events and delegates
Using events and delegates
editExam objectives: Control interactions between .NET Framework application components by using events and delegates.
(Refer System namespace)
Delegate class - MSDN
- Delegates hold pointers to one or more functions and invoke them as needed.
- One common use of delegates is for event handling. A class that raises an event does not know what objects or methods want to receive the event, so an intermediary or pointer mechanism is needed between the object raising the event and the object(s) receiving the event. Delegates can be used as function pointers to accomplish this.
- A delegate is a class, but unlike a regular class it has a signature. In the .Net framework you just declare the delegate and the CLR handles the implementation of the class.
//delegate declaration public delegate void AlarmEventHandler(object sender,EventArgs e);
- The first complete example just declare a delegate type, then declare a variable of that type, assign a function to it and execute the delegate variable which has the effect of executing the function.
C# sample
Simple delegate
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab01 { // declare the delegate type public delegate int IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Assign the delegate IntOperDel deleg = pgm.Increment; // Executing the delegate int res = deleg(32); Console.WriteLine("First value: " + res.ToString()); // Second assign deleg = pgm.Decrement; // Second execution res = deleg(32); Console.WriteLine("First value: " + res.ToString()); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to the delegate public int Increment(int n) { return n + 1; } // Second function to be assigned to the delegate public int Decrement(int n) { return n - 1; } } }
- The second delegate example implement the concept of a callback function. A function is called with a delegate as an argument. When it executes the delegate it has no knowledge of exactly what function is executed. Part of its behavior is delegated to the function passed as a parameter (thru the delegate).
C# sample
Callback delegate
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab02 { // declare the delegate type public delegate int IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Assign the delegate IntOperDel deleg = pgm.Increment; // Calling a function that will execute de delegate // as part of its own logic pgm.ExecuteCallBack(deleg); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // Function to be assigned to a delegate public int Increment(int n) { return n + 1; } // Function called with a delegate as parameter public void ExecuteCallBack(IntOperDel deleg) { int res = deleg(32); Console.WriteLine("Result from executing the callback: " + res.ToString()); } } }
- The third delegate example uses a delegate member to produce the same pattern as an event. Note that executing the delegate member without assigning at least one function will cause an exception. Also assigning 2 functions with the += operator will execute the 2 functions when the delegate is executed. If the delegate has a return code, the return value of the last executed function will be returned.
C# sample
Delegate member
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab03 { // declare the delegate type public delegate void IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(int n) { int res = n + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(int n) { int res = n - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member of the delegate type public IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { this.delMember(32); } } }
- The fourth example is the basic example of an event. It is exactly as the third example with the event keyword added to the member declaration and a test before calling the event because of the exception thrown on an "empty" event. This example shows clearly that an event is nothing more then a multicast delegate.
C# sample
Event member
using System; using System.Collections.Generic; using System.Text; // namespace DelegateLab04 { // declare the delegate type public delegate void IntOperDel(int i); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(int n) { int res = n + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(int n) { int res = n - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(32); } } }
- Executing the functions associated with an event is called raising the event.
- The functions associated with the event are called event handlers
EventArgs class - MSDN
- By convention an event uses a delegate that returns void and take 2 arguments:
- an object of type System.Object that contains a reference to the object that raised the event.
- an object from a class derived from EventArgs that contains the data passed from the object that raised the event to the event handlers.
- The EventArgs class does not contain any data by itself.
- So an event with no data will use a delegate of the form
public delegate void DelegateTypeName (object sender, EventArgs e)
- This simple event example is the same as the last one with the IntEventArgs class that serves for passing the int argument to the event handler and all the parameters changed to follow the calling convention for events.
C# sample
Event with delegate that follows the calling convention
using System; using System.Collections.Generic; using System.Text; // namespace EventLab01 { // the class containing the event data passed to the event handler public class IntEventData : EventArgs { public int IntParm = 0; // constructor public IntEventData(int i) { IntParm = i; } } // the delegate type public delegate void IntOperDel(object sender, IntEventData e); // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(object sender, IntEventData e) { int res = e.IntParm + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(object sender, IntEventData e) { int res = e.IntParm - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event IntOperDel delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, new IntEventData(32)); } } }
EventHandler delegates - MSDN and MSDN
- There are two special delegates defined in the System namespace to help you with the events declarations.
- The first is the EventHandler delegate. It passes no data. An event that passes no data can be declared as:
public event EventHandler EventName
- without having to declare a custom delegate.
- This is the usual way to declare an event that passes no data.
C# sample
Event with EventHandler delegate
using System; using System.Collections.Generic; using System.Text; // namespace EventLab03 { // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to the event public void Increment(object sender, EventArgs e) { int res = 32 + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to the event public void Decrement(object sender, EventArgs e) { int res = 32 - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event EventHandler delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, null); } } }
- The second is the EventHandler<T> generic delegate where T is a type derived from EventArgs
public event EventHandler<T> EventName
- again no need to declare a custom delegate type.
- This is the usual way to declare an event that passes data to the event handlers.
- Note that in this case you still have to declare the type T derived from EventArgs.
C# sample
Event utilizing EventHandler<T>
using System; using System.Collections.Generic; using System.Text; // namespace EventLab02 { // the class containing the event data passed to the event handler public class IntEventData : EventArgs { public int IntParm = 0; // constructor public IntEventData(int i) { IntParm = i; } } // class Program { static void Main(string[] args) { Program pgm = new Program(); // Use += oper to assign functions to the delegate pgm.delMember += pgm.Increment; pgm.delMember += pgm.Decrement; // Calling some member function that will execute the delegate pgm.ExecuteSomething(); // Wait for finish Console.WriteLine("Press ENTER to finish"); Console.ReadLine(); } // First function to be assigned to a delegate public void Increment(object sender, IntEventData e) { int res = e.IntParm + 1; Console.WriteLine("Inside increment function: " + res.ToString()); } // Second function to be assigned to a delegate public void Decrement(object sender, IntEventData e) { int res = e.IntParm - 1; Console.WriteLine("Inside decrement function: " + res.ToString()); } // Class member event of the delegate type public event EventHandler<IntEventData> delMember; // Function called to execute the delegate member (raise the "event") public void ExecuteSomething() { if (this.delMember != null) this.delMember(this, new IntEventData(32)); } } }
- This concludes the basic examples for events and delegates.