Current area: HOME -> Delegates and Event Handling in C#
|
Delegates and Event Handling in C#
Introduction:
This article will deal with Event and delegates in C#. C# Open a new door by including the feature of Event Driven programming such as Events and Delegates. This article is part of the series that helps in understanding Events and Delegates.
Events are the means by which Windows Application receive notification. In a Windows application a lot of Events are occurring at a particular instant for e.g. Mouse Move, Mouse out, Mouse Click etc. Delegates are pointer to the function and are type-safe. This Article will cover the Single delegate, Multi-cast delegates and Event Driven programming using C#. The first part of this article will focus delegates and its types and the remaining part is on Events.
Delegates:
Another very interesting feature in C# is delegates. Delegates are best complemented as new type of Object in C#. They are also represented as pointer to functions. Technically delegate is a reference type used to encapsulate a method with a specific signature and return type. Since in this article delegate discussion is event centric. If we consider a real world scenario then delegates can be understood as any delegate representing a country a group of people representing a company etc. This same definition can be mapped to C# as delegate act as an intermediary between event source and destination. The DotNetFrameWork has a Name Space System.Delagate. We have two flavors of delegate in C#.
Single Delegate
Multi-cast Delegate
Single Delegates:
A delegate is called a single delegate that derives from the System.Delegate class contains an invocation list with one method. Now we will look at how the single-cast delegates are declared. In single-cast delegates, the delegate can point to both static and non-static method if both have the same signature as the delegate. Look at the code below how to declare a single-cast delegate.
public delegate void Myfunction(string,System.Int32)
The above code shows a simple delegate which will point to a method with no return type and taking two arguments as parameters. Now we see delegate that return a value.
public delegate bool MyFunctionOne();
Consider a simple example
using System;
namespace ConsoleApplication
{
/// <summary>
/// Summary description for Name.
/// </summary>
public class Name
{
public Name()
{
//
// TODO: Add constructor logic here
//
}
public string Compare(string NameOne, string NameTwo)
{
System.Int32 result=NameOne.CompareTo(NameTwo);
if(result==0)
{
return NameOne;
}
else
{
Console.WriteLine(NameTwo +""+ NameTwo);
return NameTwo+" "+NameOne;
}
}
}
}
Description of the Above Code:
The above example doesn't show the true usage of delegates but I think we are getting the idea what we want to understand. Above is a simple program which compares two strings. If the strings are equal then only one name is returned otherwise both the names are returned if the condition executes to false. Now first the main method is invoked which is situated in DelegateExample Class. In this class we have also declared our delegate.
public delegate string CompareNames(string NameOne,string NameTwo);
It accepts two arguments of type string and also returns a string. In the main method we create the instance of Name class and then we create the instance of our delegate passing the name of our method in it as its argument so that it points to compare method now. Then we just call our delegates by passing the arguments. Which in return call the Compare method and return the string.
Multi-cast Delegates:
A delegate is called Multi-cast Delegate that derives from the System.MulticastDelegate contains an invocation list with multiple methods. At times it is desirable to call two methods through a single delegate. This can be achieved through Single-cast Delegate but it is different from having a collection, each of which invokes a single method.
In Multi-casting you create a single delegate that will invoke multiple encapsulated methods. The return type of all the delegates should be same. Now the question why are we using Multi-cast delegates when Single-cast delegates are enough. Well the answer to this question is what if you want to call three methods when a button is clicked. The Multi-cast delegates are used with events where multiple call to different methods are required. System.MulticastDelegate contains two methods Combine and Remove. The Combine is a static method of class System.MulticastDelegate and is used to Combine the delegates and the remove method is used to remove the delegate from the list. For user convenience we have += operator overloaded for delegate Combine method and -= operator overloaded for Remove method Multi-cast delegates are similar to Single-cast delegates for e.g.
public delegate void MulticastDelegate();
Multi-cast delegate can have arguments and can return value as well. All the Methods pointed by delegates should return the similar value as the delegate return type.
public delegate string MultiCastOne(string Name);
Consider a simple example:
using System;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class MyClassDelegate
{
/// <summary>
/// The main entry point for the application.
/// </summary>
public delegate string StringDelegate(string s);
}
}
Below is the class that defines the static methods having same signature as delegate.
using System;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for MyImplementingClass.
/// </summary>
public class MyClass
{
public MyClass()
{
}
public static string WriteString(string s)
{
Console.WriteLine("Writing string");
return "null";
}
public static string logString(string s)
{
Console.WriteLine("loging string");
return "null";
}
public static string TransmitString(string s)
{
Console.WriteLine("Transmitting string");
return "null";
}
}
}
The Main class:
using System;
using System.Threading;
namespace Multi_castDelegate
{
/// <summary>
/// Summary description for Test.
/// </summary>
public class Test
{
public static void Main()
{
MyClassDelegate.StringDelegate
Writer,Logger,Transmitter;
MyClassDelegate.StringDelegate myDelegate;
Writer=new
MyClassDelegate.StringDelegate(MyClass.WriteString);
/// calling Writer
Writer("hello i am Writer just acting like Single cast");
Logger=new
MyClassDelegate.StringDelegate(MyClass.logString);
///calling Logger
Logger("hello i am Logger just acting like Single-cast");
Transmitter=new
MyClassDelegate.StringDelegate(MyClass.TransmitString);
///calling Transmitter
Transmitter("hello i am Transmitter just acting like Single-cast");
///here mydelegate used the Combine method of System.MulticastDelegate
///and the delegates combine
myDelegate=(MyClassDelegate.StringDelegate)
System.Delegate.Combine(Writer,Logger);
myDelegate("used Combine");
///here Transmitter is also added using the overloaded form of Combine
myDelegate+=Transmitter;
myDelegate("Using Overloaded Form");
///now using the Remove method
myDelegate=(MyClassDelegate.StringDelegate)
System.Delegate.Remove(myDelegate,Writer);
myDelegate("Without Writer");
///overloaded Remove
myDelegate-=Transmitter;
myDelegate("Without Transmitter");
System.Threading.Thread.Sleep(2300);
}
}
}
Description of the Above Code:
The above program contains three classes, MyClassDelegate contains the delegate.
public delegate string StringDelegate(string s);
The class MyClass Contains the static methods that contains the static methods that have a similar signature as the delegate StringDelegate. The third class is the Test Class which shows how to combine the delegates and how to remove the delegate from the list.
Events:
Events are the messages sent by an object to indicate the occurrence of an event. Event can also be defined as a member that enables an object to provide notification. Events provide a very powerful means of inter-process communication. The most familiar example of events are graphical user interface, events are fired when any control is clicked on the GUI.
Events are not used only for graphical user interfaces. Events provide a generally useful way for objects to signal state changes that may be useful to the client of that object. In C# events are used with delegates. If you don't have through understanding of delegates please refer the above portion. In event communication the event raiser class doesn't know who is going to handle the event now the delegates comes into play that acts as an intermediary between the source and the receiver.
Delegate:
public delegate void newdelegate();
Event Declaration:
public event newdelegate newevent;
We can categories events into two types
Customized Events
Predefined Events
1. Customized Events:
Don't confuse these terms because I have categorized events so that the explanation become simple. Now what do we mean by customize events, they are events which we define according to our needs and are not defined. For e.g we want to raise an event whenever a dynamic control is created on the form. To declare an event, first define the delegate for that event, if none is already declared. The delegate type defines the set of argument that are to be passed to the method which will act as event handler.
Example of Customized Events:
namespace Eventhandling
{
public delegate void IamClicked();
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public System.Int32 o_IntCounter=0;
public event IamClicked ClickMe;
System.Int32 o_intXaxis=120;
System.Int32 o_intYaxis=80;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
Button b1=new Button();
b1.Parent=this;
b1.Location=new Point(o_intXaxis,o_intYaxis);
b1.Name="Click1";
b1.Text="Click Me";
ClickMe+=new IamClicked(Show);
ClickMe();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(304, 237);
this.Name = "Form1";
this.Text = "Events";
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
/// <summary>
/// Event Handler Function Which is called when the
/// Click Event is Raised.
/// </summary>
/// <param name="o"></param>
/// <param name="ea"></param>
public void Show()
{
MessageBox.Show("JUST BORN");
}
}
}
Description:
The above program shows hoe we can fire our own events. In this program a button is created dynamically.
Button b1=new Button();
b1.Parent=this;
b1.Location=new Point(o_intXaxis,o_intYaxis);
b1.Name="Click1";
b1.Text="Click Me";
ClickMe+=new IamClicked(Show);
ClickMe();
The delegate and event defined in above program are
public delegate void IamClicked();
public event IamClicked ClickMe;
The delegate points to the following function.
public void Show()
{
MessageBox.Show("JUST BORN");
}
When the ClickME event is fired the delegate attached to this event call the above function Show. Look at the signature of the function and the delegate both are same. The function just shows a message box with the message "Just Born".
2. Predefined Events:
Events and delegates go hand in hand. Now we are considering Predefined events like
Click
Closed
Closing
DragDrop
Enter
Load
Leave
etc
We normally use predefined events in our programming practice. Multiple events can share the same delegate type. The event is declared as the delegate type. In C# we must follow precise signature for Handler.
void OnClick(object o,EventArgs ea)
{
//Code
}
Example of Events:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace Eventhandling
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public System.Int32 o_IntCounter=0;
private System.Windows.Forms.Button btnNewControl;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnNewControl = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnNewControl
//
this.btnNewControl.Name = "btnNewControl";
this.btnNewControl.Size = new System.Drawing.Size(112, 32);
this.btnNewControl.TabIndex = 0;
this.btnNewControl.Text = "New Control";
this.btnNewControl.Click += new System.EventHandler(this.btnNewControl_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(304, 237);
this.Controls.AddRange(new System.Windows.Forms.Control[]
{
this.btnNewControl});
this.Name = "Form1";
this.Text = "Events";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
/// <summary>
/// Event Handler Function Which is called when the
/// Click Event is Raised.
/// </summary>
/// <param name="o"></param>
/// <param name="ea"></param>
public void btnAdd(object o,EventArgs ea)
{
o_IntCounter++;
MessageBox.Show(o_IntCounter.ToString());
}
private void btnNewControl_Click(object sender, System.EventArgs e)
{
System.Int32 b_intCount;
System.Int32 b_intXaxis=120;
System.Int32 b_intYaxis=80;
for(b_intCount=1;b_intCount<=3;b_intCount++,b_intYaxis+=20)
{
///new buttons are created at run time
///with there location and names.
Button b1=new Button();
b1.Parent=this;
b1.Location=new Point(b_intXaxis,b_intYaxis);
b1.Name="Click1"+b_intCount;
b1.Text="Click Me";
b1.Click+=new EventHandler(btnAdd);
}
}
}
}
Description:
The above program creates three buttons at run time and when any of the buttons is clicked the Click event of that button is fired.
for(b_intCount=1;b_intCount<=3;b_intCount++,b_intYaxis+=20)
{
///new buttons are created at run time
///with there location and names.
Button b1=new Button();
b1.Parent=this;
b1.Location=new Point(b_intXaxis,b_intYaxis);
b1.Name="Click1"+b_intCount;
b1.Text="Click Me";
b1.Click+=new EventHandler(btnAdd);
}
The Click event belongs to the button class. We will reference it when we are registering a delegate.
b1.Click+=new EventHandler(btnAdd);
The delegate EventHandler is also defined in the System namespace of Dot net Framework library. All what we have to do is to define our callback function that is invoked when the button is clicked and accepts two arguments object and EventArgs type conforms the signature of delegate EventHandler defined in System namespace
public void btnAdd(object o,EventArgs ea)
{
o_IntCounter++;
MessageBox.Show(o_IntCounter.ToString());
}
The handler btnAdd() Method catches this event and shows a message box that indicates a number that how many times these buttons are clicked. The above example is quite self explanatory so just copy the code in a new project and run for yourself.
About the author
Faisal Jawaid is a software engineer in Pakistan and working in professinal enviroment for a year. He has programming experience of Java,Vb6 Scripting Languages like javaScript, HTML,CSS etc.Currently working on DotNet technologies like C# and VbDotNet.
|