TERRYSMITH.NET    Doing Objects in VB.NET and C# - EVENTS AND DELEGATES  
             Home              Painting              Photography              Software              Writing
Previous ] [ Index ] [ Next ]   

4

Events and Delegates

There are some confusing, but generally quite minor differences, between how events are declared, raised, and handled in VB.NET versus C#. Events are a simple concept and were painless to implement in VB 6.0. All of the message wiring was handled for you behind the scenes. Luckily, we can thank Microsoft for saving our naive minds from certain death by boredom by introducing delegates.

Seriously though, delegates are not very complicated, and in any case, you don't have any choice in using them if you want to make your code more eventful. A delegate is a type-safe function pointer. Once you have one you can point it to any method that matches the delegate's method signature and return type. Then, any call on the delegate, which is just a pointer to a function with the same signature, passes through to the method that it points to.

It's easy to see how .NET implements events. A collection of delegates is kept internally and, when an event is raised, each delegate is called (i.e. delegated to) in round-robin fashion. This is simply an implementation of the Observer design pattern (see Design Patterns by Gamma et. al.).

Declaring Events

Visual Basic .NET thinly hides the use of delegates from you. The syntax for declaring one is the same as it was in VB 6.0:

Public Event TotalUpdatedEvent(ByVal Amount As Decimal)

It's not so transparent in C#. You first must define a delegate and then declare an event of that delegate type:

public delegate void totalUpdatedEventHandler(decimal amount);
public event totalUpdatedEventHandler totalUpdatedEvent;

There's one more important difference. Notice the void in the C# code above. Event handlers for this particular event cannot return a value; however, it is possible for handlers in C# to return values. This is not allowed in VB.NET where all handlers must be Subs. Instead, in VB.NET events can pass ByRef parameters. A Cancel argument on a Closing event is a common example.

Raising Events

The differences between VB.NET and C# for raising events are rather uneventful:

RaiseEvent TotalUpdatedEvent(123.45)

versus the following in C#:

totalUpdatedEvent(123.45);

Implementing Event Handlers

There are two ways to implement event handlers in VB.NET. The most common method is to define a handler at design time with the Handles keyword. The object instance raising the event must be declared with the WithEvents keyword, a carryover from VB 6.0 as shown below:

Module modMain
   Private WithEvents calculator As calculator = New calculator()

   Public Sub Main()
      Call calculator.DoSomethingEventful()
   End Sub

   Private Sub TotalUpdated(ByVal Amount As Decimal) Handles calculator.TotalUpdatedEvent
      Trace.Write("Total was updated to " + Amount.ToString())
   End Sub
End Module

Public Class Calculator
   Public Event TotalUpdatedEvent(ByVal Amount As Decimal)

   Public Sub DoSomethingEventful()
      RaiseEvent TotalUpdatedEvent(123.45)
   End Sub
End Class

The second method is to associate a handler function with an event at run time by using AddHandler together with AddressOf like so:

Module modMain
   Private WithEvents calculator As calculator = New calculator()

   Public Sub Main()
      AddHandler calculator.TotalUpdatedEvent, AddressOf TotalUpdated

      Call calculator.DoSomethingEventful()
   End Sub

   Private Sub TotalUpdated(ByVal Amount As Decimal)
      Trace.Write("Total was updated to " + Amount.ToString())
   End Sub
End Module

In C# all handlers must be associated at run time. This example demonstrates the handling of events in C#:

public class EventReceiver
{
   static void Main(string[] args)
   {
      EventReceiver demo = new EventReceiver();
      demo.doDemo();
   }

   public void doDemo()
   {
      Calculator calculator = new Calculator();

      Calculator.totalUpdatedEventHandler handler = new Calculator.totalUpdatedEventHandler (OnTotalUpdated);
      calculator.totalUpdatedEvent += handler;

      calculator.doSomethingEventful();
   }

   public void OnTotalUpdated(decimal amount)
   {
      Trace.Write("Total was updated to " + amount.ToString());
   }
}

internal class Calculator
{
   public delegate void totalUpdatedEventHandler(decimal amount);
   public event totalUpdatedEventHandler totalUpdatedEvent;

   public void doSomethingEventful()
   {
      totalUpdatedEvent(123.45M);
   }
}

Here are a few more things you should know about events:

  1. Handlers can be removed at run time with RemoveHandler and the -= operator.
  2. Handlers are executed in the order they were associated.
  3. When multiple handlers are associated with a single event in C# and the handler signature has a return type, then the value returned by the last handler executed will be the one returned to the event raiser.
  4. Visual Basic .NET provides default delegate types for you. But wait! Microsoft's endless generosity doesn't stop there. Default delegates are also provided for the events of the .NET Framework's controls and classes. Therefore, you only need to worry about delegates when you're defining your own events in C#.
Previous ] [ Index ] [ Next ]   

Amazon Honor System Click Here to Pay Learn More


All images and text on this site are licensed only for viewing on your computer during your visit. No rights to save, copy, print, redistribute, use in derivative works, or in any other manner are allowed or implied without the prior written consent of the author.

All images and text are ©Terry Smith unless otherwise noted. All rights reserved.

terry@terrysmith.net