Those of us who have been playing with C# over the years have gotten used to the concepts of a delegate and an event but what use are they and how do we implement them?

Basically, an event is something that happens within the application and the application notifies the rest of the application about this event taking place. This could be useful for other parts of the application to take advantage of.

A delegate is a reference that allows you to run code based on the event that has taken place. But what use is that? It sounds all well and good but why would we want to do this?

Well, how about we write a game that has things shooting at each other. We don’t really want to write code that keeps checking things all the time. It’s much quicker and easier to just let the application tell you something has happened and react to it. So how do we do this?

Ok, here is a simple class:


namespace EventsAndDelegates
{
public class Firing
{
public event FireHandler Shot;
public delegate void FireHandler(Firing f, ShotOnTarget e);
public void Start()
{
while (true)
{
System.Threading.Thread.Sleep(1000);
if (Shot != null)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);

ShotOnTarget SOT = new ShotOnTarget();
if (randomNumber > 80)
SOT.HitTheTarget = true;
else
SOT.HitTheTarget = false;
Shot(this, SOT);
}
}
}
}
}

This basically has a method that continuously loops. The method pauses for a second then generates a random number between 0 and 100, if the number is over 80 it sets the event’s argument ‘HitTheTarget’ to true, otherwise it’s set to false. It then fires the event indicating a shot has occurred.

Also, to make things a little easier on the eye, an EventArg class:


namespace EventsAndDelegates
{
public class ShotOnTarget : EventArgs
{
private bool wasHit;
public bool HitTheTarget
{
set
{
wasHit = value;
}
get
{
return wasHit;
}
}
}
}

This is nothing special, it just allows us to put data into the Event arguments which could come in useful later on…

Now the main form:


namespace EventsAndDelegates
{
public partial class frmMain : Form
{
private Firing fir;
private Thread oThread;
delegate void SetFireCallback(Firing f, EventArgs e);

public frmMain()
{
InitializeComponent();

fir = new Firing();
Subscribe(fir);
}

private void btnFire_Click(object sender, EventArgs e)
{
oThread = new Thread(fir.Start);
oThread.Start();
}

public void Subscribe(Firing f)
{
f.Shot += Hit;
}

private void Hit(Firing f, EventArgs e)
{
if (lbFeedback.InvokeRequired)
{
SetFireCallback d = Hit;
Invoke(d, new object[] { f, e });
}
else
{
ShotOnTarget feedback = (ShotOnTarget) e;
if (feedback.HitTheTarget)
lbFeedback.Items.Add("Hit the target");
else
lbFeedback.Items.Add("Missed the target");
}
}

private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
// Stops crashing while closing form
oThread.Abort();
}
}
}

As you can probably work out, the form consists of a button called btnFire and a ListBox called lbFeedback. When you start the application, you are presented with the button and the empty listbox. Behind the scenes, the main form subscribes the Hit Method to the Firing delegate (which is observing the Shot event) allowing us to get feedback when the event is fired.

Now if we click the button, we create a thread that runs forever. This thread will contain the Firing object and will be running the Start routine within the object. As you know, every second the Start method will be taking a shot and reporting if it has hit or missed its target to the Shot event. Since we have subscribed the Hit method in the main form to the delegate, each time the event is fired, the Main Form’s Hit even gets fired also. Pretty neat eh? There is some code to allow safe threading to take place (for the curious, you can’t access objects via separate threads but you can create a local object with the same data which you can access. You create the local object, then call the Hit method again with the new objects and we don’t get an exception!) but then we add text to the ListBox. Either a hit or a miss notification.

The final method (formMain_FormClosing) just kills the thread before we close the applicaton or we get another exception when closing the application once we’re done.

So there you have it, Events and Delegates in a fairly simple example. Using this functionality should significantly help people componentise their code and allow them to be able to drop whole classes easily into other applications with practically no code changes to the class required! Much, much easier in the long run!

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)