Struggling for Competence

C# Events

An event provides an extensibility point to a class. An event lets a publisher notify subscribers when something happens. Typically the publisher is a vendor supplied UI widget, and the subscriber is the code you are writing.

There are two stages to using an event:

  1. Attach your method to the event.
  2. When the event fires your method gets called.

There are some rules about events which are useful to understand:

The following code is a contrived example which illustrates using an event. Say you have a UI button which raises the "ButtonClick" event. You want to display some text when the button is clicked:


using System;
using MbUnit.Framework;

namespace EventDemo
{
    [TestFixture]
    public class EventTest
    {
        public class UiButton
        {
            public event EventHandler ButtonClick;

            public virtual void OnButtonClick()
            {
                if (ButtonClick != null)
                {
                    ButtonClick(this, new EventArgs());
                }
            }
        }

        public class CodeBehind
        {
            public UiButton widget = new UiButton();

            public string TextBoxText { get; set; }

            public void PageLoad()
            {
                widget.ButtonClick += HandleOnClick;
            }

            private void HandleOnClick(Object sender, EventArgs e)
            {
                TextBoxText = "ButtonClicked";
            }
        }

        [Test]
        public void Framework()
        {
            CodeBehind behind = new CodeBehind();
            behind.PageLoad();
            Assert.AreEqual(null, behind.TextBoxText);

            behind.widget.OnButtonClick();
            Assert.AreEqual("ButtonClicked", behind.TextBoxText);
        }
    }
}

If this were real code you would only be writing the CodeBehind class. The UiWidget and Framework code would be hidden away in the vendor library. This is one of the aspects which I think makes understanding events tricky; you typically only see a small part of what's going on.

In the "PageLoad" method the HandleOnClick method is attached to the ButtonClick event. There are a number of approaches for attaching a method to the event:

The signature of the event-handling method must match the signature of the event-handler delegate. So in the example, the HandleOnClick method must match the method signature of the EventHandler delegate:

public delegate void EventHandler(Object sender, EventArgs e);

The event handler delegate will always look similar to this. The only variation is in the type of the EventArgs parameter. This is because the delegate follows the following conventions:

These conventions don't have to be followed. Take the first one - the return type should be void. Before I read up about events, I defined my own event with a custom delegate which returned an int. It would have gone badly wrong though, if another developer added a second method to the event. In that case I shouldn't have used an event at all - just a straight delegate would have been fine.