AddThis Social Bookmark Button

Print

Writing C# Custom Events

by Budi Kurniawan
04/15/2002

Anyone doing Windows programming must have done some event handling in some way or another: capturing the double-click of a button, handling the click of a menu item, reacting to the moving of the mouse pointer over a label, and so forth. But what about creating your own event, in your own control, and letting others capture that event? In this article, you will learn how to use the observer design pattern to raise and handle events for your .NET control and learn how to pass event argument data.

An event is a message sent by an object to notify other objects that an action has occurred. The action could be user-initiated, such as a mouse click, or it could be triggered by some other program logic. The object that raises the event is called the event sender, and the object that receives the event notification is called the event receiver. The event receiver has a method that gets executed automatically in response to the event.

The .NET Framework supports easy event-driven Windows programming. It's so easy that often the programmer does not have to know how events work in the underlying .NET technology. All one has to remember is this: if you are interested in receiving an event from a Windows control, you provide an event handler and register the event handler with the event source. This is called event wiring. In C#, you need to write a line of code of the following syntax, normally in the class' constructor of your form.


eventSource.someEvent += new SomeEventHandler(someMethod);

For instance, if you want to handle the Click event of a button named button1, and you want the private button1_Click method to be executed when the Click event occurs, you write the following.


button1.Click += new EventHandler(button1_Clicked);

Then, you must also provide the implementation of button1_Click in your class, as follows.


private void button1_Clicked(Object sender, EventArgs e)
{
  // code to be executed when the Click event occurs
}

The method does not have to be private, but it must accept two arguments: an object of type Object and an EventArgs object. So consuming events is a piece of cake. Now, let's have a look at creating your own custom event that other programmers can use. Before we do this, however, we should first discuss the observer pattern in object-oriented programming.

The Observer Pattern

There are two key objects in this pattern: the subject and the observer. The subject may have one or many observers. These observers listen for notification from the subject of a state change inside the subject. This pattern is also known asdependence or publish-subscribe. According to The Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides) in their book Design Patterns: Elements of Reusable Object-Oriented Software, the Observer pattern can be applied in the following situations:

Related Reading

Programming C#
By Jesse Liberty

  • When an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently.
  • When a change to one object requires changing others, and you don't know how many objects need to be changed.
  • When an object should be able to notify other objects without making assumptions about who these objects are. In other words, you don't want these objects to be tightly coupled.

In event communication, the event sender class does not know which object or method will receive the events it raises. What is needed is an intermediary (or pointer-like mechanism) between the source and the receiver. The .NET Framework defines a special type, Delegate, that provides the functionality of a function pointer.

A delegate is a class that can hold a reference to a method. Unlike other classes, a delegate class has a signature, and it can hold references only to methods that match its signature. A delegate is thus equivalent to a type-safe function pointer, or a callback. The next section describes how to use delegates to communicate an event from an object to another object. The section after that puts the theory into practice by providing a control that has two custom events.

Writing a Custom Event -- Step-by-Step

Suppose you want to write a custom event called MyEvent for your custom control named MyControl that extends System.Windows.Forms.UserControl. Here are the steps you need to take.

1. Declare a delegate with the public access modifier. Here I will call this delegate MyEventHandler, and it has two arguments: an object called sender and MyEventArgs called e. We will define MyEventArgs later. Note that the delegate must be declared outside of your control class.


public delegate void MyEventHandler(object sender, MyEventArgs e);
public class MyControl: UserControl
{
   ...
}

2. MyEventArgs in Step 1 is the object that contains the data that can be passed from the event sender (MyControl) to the event receiver. MyEventArgs must extend the System.EventArgs class. Therefore, you now have the following code:


public class MyEventArgs: EventArgs
{
  ...
}

public delegate void MyEventHandler(object sender, MyEventArgs e);

public class MyControl: UserControl
{
   ...
}

There is some implementation you need to write inside the MyEventArgs class, but we will leave it until later.

3. In your control class, declare an event called MyEvent.


public class MyEventArgs: EventArgs
{
  ...
}

public delegate void MyEventHandler(object sender, MyEventArgs e);

public class MyControl: UserControl
{
  public event MyEventHandler MyEvent;
   ...
}

4. In your control class, declare a protected virtual method named On plus the name of the event. Since our event in this example is called MyEvent, the method is called OnMyEvent. Note that OnMyEvent has one argument of type MyEventArgs. Inside of this method, you raise the event. In C#, raising an event is achieved by calling the event name. To raise the event, you pass two arguments: the sender (the control MyControl) and the MyEventArgs object passed to the method.


public class MyEventArgs: EventArgs
{
  ...
}

public delegate void MyEventHandler(object sender, MyEventArgs e);

public class MyControl: UserControl
{
  public event MyEventHandler MyEvent;
  protected virtual void OnMyEvent(MyEventArgs e)
  {
    MyEvent(this, e)
  }
   ...
}

5. Now, the only step left is to actually call OnMyEvent from somewhere in the MyControl class. How you do this depends on what should cause the event to occur. This will become clear in the next section, when I present the real control that implements two events. Afterwards, users of your control can consume the MyEvent event in your control by wiring the event to an event handler in their form, as shown at the beginning of this article. Now, let's see the real code with two events and demonstrate how these events can be raised and consumed.

Pages: 1, 2

Next Pagearrow