U2U Article: "Programming with delegates and events in .NET" Copyright © 2002 by U2U nv/sa, Belgium. All rights reserved.
Please address any questions or suggestions to U2U.

Programming with delegates and events in .NET

Author: Wim UYTTERSPROT, wim@u2u.be

Part 1: Introducing Delegates
Part 2: Defining your own Delegate class

Part 3: Delegates Example: The Programmable Robot
Part 4: Introducing .NET Events
Part 5: .NET Events Example: The Programmable Robot(2)

Part 4: Introducing Events

Now that we understand the delegate’s principles, let us look how events are handled.

Events notify client objects of an action; for example, the controls in a GUI are event-driven.  Windows applications are event-driven. An event is often a change of state: a change in the mouse position, a change in the mouse button position, a change of the keyboard state as a key is pressed, etc. Event references are defined using the delegate type.

The message sending mechanism

The message sending mechanism is a simple object-oriented mechanism that takes place between two objects, the first of which (the client) sends a message to the second one (the server). The server offers services to clients. A client will question a server via the well-known dot-protocol:

server.askforservice(arg)

 

The event handling mechanism

The event mechanism is an object-oriented mechanism that takes place between one server object sending an event to all client objects registered for this event.

In .NET, the server object sending event messages to all registered client objects realizes the event mechanism. To that end, clients need to make themselves known to the server and send a delegate object to the server. This delegate object represents the client in the server object: whenever an event needs to be sent, the server will address the delegate object, which in turn will call the client’s event handler.

In .NET, the following steps implement the event mechanism, where we suppose to have one server instance and two or more client instances:

  • Define a delegate class determining the signature of the event and the event handler.
  • In the server class, define en event reference.
  • Raise the event from the server class.
  • In the client class, define an event handler function according to the signature of the delegate class.
  • Hook up the event handler function of each client object to the event of the server.

Starting with the Server class

We start from a server class with only one private data member, namely thevalue, accessible via the accessor value:

public class Server
{
  public double Value
  {
    get
    {
      return thevalue;
    }
    set
    {
      thevalue = value;
    }
  }
  private double thevalue = 0.0;
}
Public Class Server

  Public Property Value() As Double
    Get
      Return thevalue
    End Get
    Set(ByVal Value As Double)
      thevalue = Value
    End Set
  End Property

  Private thevalue As Double = 0
End Class

Defining a delegate class

We need to inform the clients of our Server class when the internal value thevalue changes: in our example, the server wants to make both the initial and the new value knowable to its clients.

We first of all define a delegate which signature looks as follows:

C#

public delegate void ValueChangedDelegate(double initialvalue, double newvalue);

VB.NET

Public Delegate Sub ValueChangedDelegate(ByVal initialValue As Double, _
ByVal newValue As Double)

We want to emphasize again that this delegate will represent the client’s event handler in the server.

Defining an event

In the server class we now define an event that is an instance of the delegate. The event is typically a public field named ValueChangedEvent and instantiates the delegate ValueChangedDelegate:

C#

public class Server
{
    public event ValueChangedDelegate ValueChangedEvent;
    
    ...
}

VB.NET

Public Class Server
    Public Event ValueChangedEvent As ValueChangedDelegate
    ...
End Class

Raising an event

Analogously to a delegate object calling the function it represents, we have the event object send out itself.

C#

In C#, the event raising code is similar to the delegate invocation code.

public class Server
{
  public event ValueChangedDelegate ValueChangedEvent; 

  public double Value
  {
    get
    {
    return thevalue;
    }
    set
    {
      if ( ValueChangedEvent != null )
      {
     
  ValueChangedEvent(thevalue, value); // invokes the event
      }
      thevalue = value;
    }
  }
private double thevalue = 0.0;
}

VB.NET

In VB.NET, the code we need to write differs from before; we have to use the RaiseEvent keyword in order to raise the event:

Public Class Server
  Public Event ValueChangedEvent As ValueChangedDelegate

  Public Property Value() As Double
    Get
      Return thevalue
    End Get
    Set(ByVal Value As Double)
      RaiseEvent ValueChangedEvent(thevalue, Value) ' invokes the event
      thevalue = Value
    End Set
  End Property

  Private thevalue As Double = 0
End Class

Before invoking the event, we should check if any client registered for it. The comparison with null checks if there is at least one client listening.

Defining an event handler in the client class

An event handler is a method bound to an event. In the client class, we define a procedure with signature corresponding to that of the delegate. This procedure will serve as event handler. In our example, this becomes:

C#

public class Client
{
  public Client(string name)
  {
    this.name = name;
  }

  /// Event handler to be hooked up to the event 
  public void ValueChangedEventHandler (double oldvalue, double newvalue)
  {
    Console.WriteLine(name + ": server value " + oldvalue 
                      + " changed to " + newvalue);
  }

  private string name;
}

VB.NET

Public Class Client
  Public Sub New(ByVal name As String)
    Me.name = name
  End Sub

  ' Event handler to be hooked up to the event
  Public Sub ValueChangedEventHandler(ByVal oldvalue As Double, _
                                      ByVal newvalue As Double)
    Console.WriteLine( name & ": server value " & oldvalue _
                       & " changed to " & newvalue)
  End Sub

  Private name As String
End Class

Instantiating server and client objects

For the moment we only have server and client classes. As the event mechanism functions on the level of the objects, we still need to instantiate server and client objects. We have to instantiate the object containing the event declaration and instantiate at least one object containing the event listener. In our example, we instantiate 1 server object and 2 client objects:

C#

Server server = new Server();
Client client1 = new Client("client 1");
Client client2 = new Client("client 2");

VB.NET

Dim server As New Server()
Dim client1 As New Client("client 1")
Dim client2 As New Client("client 2")

Linking the event handlers to the events

In order to link the event handler of the client to the event of the server, we make use of a delegate object:

C#

server.ValueChangedEvent += new ValueChangedDelegate(client1.ValueChangedEventHandler);

VB.NET

AddHandler server.ValueChangedEvent, AddressOf client1.ValueChangedEventHandler

We have here the member function ValueChangedEventHandler of client1 represented by a new delegate object. The event-delegate binding is dynamic: it is created at run time. We link the delegate object to the event ValueChangedEvent of the server using the += operator. In fact, as for delegates, the only operators allowed are += to add a binding and -= to remove one.

In the same way we link a second event handler (here even of a different object) to the same event/

C#

server.ValueChangedEvent += new ValueChangedDelegate(client2.ValueChangedEventHandler);

VB.NET

AddHandler server.ValueChangedEvent, AddressOf client2.ValueChangedEventHandler

Testing the event handling mechanism

Finally, we execute the following simple test, which sends out the event in the server, the event being dealt with in the event handlers of the 2 clients:

server.Value = 100

The result on the console confirms that an event is caught by two event handlers.

client 1: server value 0 changed to 100
client 2: server value 0 changed to 100

Complete code of this example in C#

public delegate void ValueChangedDelegate(double initialvalue, double newvalue); 

  public class Server
  {
    public event ValueChangedDelegate ValueChangedEvent; 

    public double Value
    {
      get
      {
        return thevalue;
      }
      set
      {
        ValueChangedEvent(thevalue, value); // invokes the event
        thevalue = value;
      }
    }
    private double thevalue = 0.0;
  }

  public class Client
  {
    public Client(string name)
    {
      this.name = name;
    }

    /// Event handler to be hooked up to the event 
    public void ValueChangedEventHandler (double oldvalue, double newvalue)
    {
      Console.WriteLine(name + ": server value " + oldvalue 
                        + " changed to " + newvalue);
    }

    private string name;
  }

  public class Test
  {
    public static int Main(string[] args)
    {
      Server server = new Server();
      Client client1 = new Client("client 1");
      Client client2 = new Client("client 2");

      server.ValueChangedEvent 
        += new ValueChangedDelegate(client1.ValueChangedEventHandler);
      server.ValueChangedEvent 
        += new ValueChangedDelegate(client2.ValueChangedEventHandler);
      server.Value = 100;

      return 0;
    }
}

Complete code of this example in VB.NET

Public Delegate Sub ValueChangedDelegate(ByVal initialValue As Double, _
                                         ByVal newValue As Double)

  Public Class Server
  Public Event ValueChangedEvent As ValueChangedDelegate

  Public Property Value() As Double
    Get
      Return thevalue
    End Get
    Set(ByVal Value As Double)
      RaiseEvent ValueChangedEvent(thevalue, Value) ' invokes the event
      thevalue = Value
    End Set
  End Property

  Private thevalue As Double = 0
End Class

Public Class Client
  Public Sub New(ByVal name As String)
    Me.name = name
  End Sub

  ' Event handler to be hooked up to the event 
  Public Sub ValueChangedEventHandler(ByVal oldvalue As Double, _
                                      ByVal newvalue As Double)
    Console.WriteLine(name & ": server value " & oldvalue _
                      & " changed to " & newvalue)
  End Sub

  Private name As String

End Class

Module Test
  Sub Main()
    Dim server As New Server()
    Dim client1 As New Client("client 1")
    Dim client2 As New Client("client 2")

    AddHandler server.ValueChangedEvent, _
      AddressOf client1.ValueChangedEventHandler
    AddHandler server.ValueChangedEvent, _
      AddressOf client2.ValueChangedEventHandler
    server.Value = 100
  End Sub

End Module

See also:

Part 1: Introducing Delegates

Part 2: Defining your own Delegate class

Part 3: Delegates Example: The Programmable Robot

Part 4: Introducing .NET Events

Part 5: .NET Events Example: The Programmable Robot(2)


Read more next week:

Part 6: The Scribble Application

Part 7: Visual Inheritance with Windows Forms

Contact me Contact


Contact me Receive U2U Newsletter.
Looking for a challenging job Download Brochure On Site Training Looking for a challenging job
Favorites Favorites

Copyright © 1999-2010 by U2U