Event Refresher

In this ever-growing world of online Web-enabled apps, it's not very often these days that we see .NET events being used much anymore.

If, like me, however, you went through the mill of writing Desktop Applications using WinForms, events and how they work should be pretty much burned into your thoughts, just as much as the .NET framework itself.

Just because we live in an online world these days, it doesn't mean, however, that there's no need for events, or that they no longer have a place in modern day coding. In fact, events actually can still be a very useful method of allowing your classes, objects, and sub-assemblies to signal things to each other.

What Exactly Is an Event?

In a nutshell, you can think of an event as a method of sending a message or signal elsewhere in an application. If you've used systems like "Redis" and its "Pub/Sub" capabilities, you've used a kind of Event-based system, but one that extends outside of application boundaries. When you're doing data binding in a WPF application, your MVVM framework is raising "Property Changed" events on your behalf, and then your UI then responds to these events and updates its data. Web UI kits like KnockoutJS do the same, but for the most part it's all magically wired up for you, so you often don't really get to see it.

Events are exceptionally useful for keeping different parts of an application in sync or for notifying something that something has happened.

Under WinForms, for example, when a button was clicked on your UI, an event would be raised by the form telling you which button was clicked.

In a program that monitors a GPS device, for example, you might find that you get an Event when a position changes, or when the speed you're traveling updates.

Creating your own events often means that you can decouple your objects from each other very easily, promoting loose cohesion when building complex applications. If you couple this loose design with something like an IoC framework, you find for the most part, that very often your objects don't need to know or care what's using them or how.

Under .NET, the central key to making good use of events is understanding what a "Delegate" is.

Delegates? They Attend Events, Right?

Almost :-) (And no I have no idea if the whole event/delegate thing has any reference to physical events…)

Delegates are function prototypes that describe the shape of function to .NET. Take the following example:

public delegate string MyFunc(int aNumber, string aString);

This would describe to .NET a function that returns a string and takes two parameters and int and a string when it's invoked. If you had:

public string foo(int age, string name)
{
}

in your application, that function would be a match for the shape of the delegate describing it.

Delegates are important when using events because they tell the event system the shape of the handler in the "Event Target" that is to be called when the event is raised.  Without delegates, .NET would have no way of knowing (or, for that matter, being able to strongly type) the type and calling parameters of the function to call, when sending out the signal that an Event has occurred.

Fire up Visual Studio, start a console mode program, and enter the following code in Program.cs:

namespace events_refresher
{
   public delegate string MyFunc(int aNumber,
   string aString);

   class Program
   {
      static void Main()
      {

      }

   }
}

You'll see that what we've created is an empty main function, and defined a delegate to describe our event function's shape.

Next, just after the opening { following "Class Program", add the following line:

public event MyFunc ProgramEvent;

What you've just done here is told .NET that you now want to define an event, that you're going to raise, and that event should call a target function that matches the shape of the delegate you previously defined.

Once we've done this, we can simply anytime we want to invoke the event. Do the following:

var handler = ProgramEvent;
handler(123, "Hello");

This, however, is considered bad practice. If the consumer of your event has not yet added a handler to your object, calling your event straight off like this could result in you causing a "Null Reference Exception." Instead, a better way is to create an "Event Invoker," something that looks like the following:

protected virtual string OnProgramEvent(int anumber,
   string astring)
{
   var handler = ProgramEvent;
   if (handler != null) return handler(anumber,
      astring);
   return "";
}

This checks your event for null before calling it, meaning that you don't get any nasty surprises should the user of your code not be subscribing to your event at the time.

Demonstrating how this works properly is a little difficult in a standard program, so add a new class to your project, called "EventTest.cs", and make sure it has the following code in it.

using System;
using System.Threading;

namespace events_refresher
{
   public delegate void MyEventTestDelegate(int aNumber,
      string aString);

   public class EventTest
   {
      public event MyEventTestDelegate SomeThingHappened;

      public void SomePublicFunction()
      {
         Console.WriteLine("Some Public Function was called");
         Thread.Sleep(5000);    // Wait for 5 seconds
         OnSomeThingHappened(123, "Hello");
      }

      protected virtual void OnSomeThingHappened(int anumber,
         string astring)
      {
         var handler = SomeThingHappened;
         if (handler != null) handler(anumber, astring);
      }

   }

}

Update your rogram.cs file so that it's returned back to its initial state:

namespace events_refresher
{
   class Program
   {
      static void Main()
      {

      }

   }
}

Now, let's add a reference to our event test class, create a new object, and call its public function.

While you're typing out the code that we're about to add, you should see that Intellisense correctly picks up the event handler in your new class:

Event1
Figure 1: Intellisense showing our event

The code in Program.cs now should look like the following:

using System;

namespace events_refresher
{
   class Program
   {
      static void Main()
      {
         var eventTest = new EventTest();
         eventTest.SomeThingHappened +=
            EventTestSomeThingHappened;

         Console.WriteLine("Calling some public function");
         eventTest.SomePublicFunction();

         Console.WriteLine("Waiting for the return key to be
            pressed to exit...");
         Console.ReadLine();

      }

      static void EventTestSomeThingHappened(int aNumber,
         string aString)
      {
         Console.WriteLine("Something Happened with
            number {0} and the text {1}!", aNumber, aString);
      }

   }
}

I've added in a five second delay, just so you can see the effect of the event being called. In reality, however, you'd likely trigger this in another thread, or some place that otherwise isn't holding up the main execution path.

For now, however, this is enough to show the simplicity that .NET events have for sending messages between your application objects.

The world of .NET is full of strange odds and ends. If you've seen one that you didn't understand, or just want to know how something works, drop me a comment below or shout at me via @shawty_ds on Twitter; I'll most likely do a post on it.



About the Author

Peter Shaw

As an early adopter of IT back in the late 1970s to early 1980s, I started out with a humble little 1KB Sinclair ZX81 home computer. Within a very short space of time, this small 1KB machine became a 16KB Tandy TRS-80, followed by an Acorn Electron and, eventually, after going through many other different machines, a 4MB, ARM-powered Acorn A5000. After leaving school and getting involved with DOS-based PCs, I went on to train in many different disciplines in the computer networking and communications industries. After returning to university in the mid-1990s and gaining a Bachelor of Science in Computing for Industry, I now run my own consulting business in the northeast of England called Digital Solutions Computer Software, Ltd. I advise clients at both a hardware and software level in many different IT disciplines, covering a wide range of domain-specific knowledge—from mobile communications and networks right through to geographic information systems and banking and finance.

Related Articles

Comments

  • Sequence of execution

    Posted by Clinton Yeboah on 11/26/2015 11:05am

    Hi Peter, Nice name though :). Thanks for this short guide. It has taught me a lot as a beginner to C#. I want to ask you for a favour. Can you explain how the program is working. How are the delegates and the events being called and handled. I have the code working, butt don't understand how the calls are being made. Thank you. I think it will ne helping to me, when I try to implement my own. Thanks again!!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date