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:
Read more next week:
Part 6: The Scribble Application
Part 7: Visual Inheritance with Windows Forms
|