Click here to monitor SSC
  • Av rating:
  • Total votes: 176
  • Total comments: 27
Amirthalingam Prasanna

Custom Events in VB.NET 2005

26 September 2005

Creating custom events with Visual Basic .NET 2005

Visual Basic .NET is well known for its event-driven programming capabilities. VB.NET 2005 adds new functionality for custom events that provides flexibility in handling and controlling events.

Events model in VB.NET

Events are defined as actions or occurances of interest. An interested object can subscribe to an event and be notified when it happens. For example, a button on a form can generate a click event and the form can subscribe and get notified when the event occurs. This click event is processed through the form code.

VB.NET 2005 provides a range of flexible event models to address simple or very complex events. Below is an example of a simple event using a Worker class with a DoWork method:

  Public Class Worker 
    Public Sub DoWork() 
      For completedWork As Integer = 1 To 100 
        System.Threading.Thread.Sleep(1000)
        Console.WriteLine(completedWork)
 
      Next
    End Sub 
  End Class

The DoWork method has a For loop repeating 100 times, waiting one second between loops, and printing out the completed work to the console. But a client such as a form using the object of the above class, for example, should provide visual feedback on how much work has been completed when the DoWork method is called. Adding an event to the Worker class and altering the DoWork method to call the event can provide this information to the client.

 Public Class Worker
 
    Public Event WorkDone(ByVal completedWork As Integer) 
    Public Sub DoWork()
 
      For completedWork As Integer = 1 To 100 
        System.Threading.Thread.Sleep(1000)
        RaiseEvent WorkDone(completedWork)
        Console.WriteLine(completedWork)
 
      Next 
    End Sub 
  End Class 

An event called WorkDone has been identified with an integer argument through which the amount of work completed can be passed. And in the DoWork method, the event passing the actual amount of work completed is raised. Now the above class can be consumed by a client by declaring and creating a Worker class object with events and handling the WorkDone event to provide feedback on progress.

Private WithEvents mWorker As New Worker
Private Sub work_WorkDone(ByVal completedWork As Integer) Handles mWorker.WorkDone
End Sub

In the above code, the work_WorkDone method will be called each time the WorkDone event is raised. The Handles clause after the method signature links the event-handling code with the actual event.

A method can also dynamically link to an event using the AddHandler method and be removed from handling an event using the RemoveHandler method as seen below. This enables more flexibility by relating a method to an event and removing the binding required at runtime. Even when the Handles keyword is used to bind a method to an event internally, a call to the AddHandler method is done to perform the actual binding.

‘We dont require to use WithEvents since we are binding to events dynamically
Private mWorker As New Worker

'Binds a method(handler) to an event
AddHandler mWorker.WorkDone, AddressOf work_WorkDone
'Unbinds a method(handler) from an event
RemoveHandler mWorker.WorkDone, AddressOf work_WorkDone

Delegates in .NET events

VB.NET implements events through a construct called delegates. Delegates point to a method and can hold the address of a method, enabling a method to be invoked through an instance of its delegate. The Worker class can be implemented without events using a delegate as follows:

 Public Class Worker
 
    Public Delegate Sub WorkDone(ByVal completedWork As Integer )
    Public Handler As WorkDone
    Public Sub DoWork() 
      For completedWork As Integer = 1 To 10
 
        System.Threading.Thread.Sleep(1000)
        If handler IsNot Nothing Then
          handler(completedWork * 10)
        End If
        Console.WriteLine(completedWork)
 
      Next 
    End Sub 
  End Class 

In the code above, a delegate named WorkDone that accepts an integer argument has been defined. This delegate can point to any method with a similar signature (a sub-procedure that accepts an integer). After the delegate is defined, a public variable delegate named Handler has been defined, and instead of raising the event in the DoWork method, the delegate instance is invoked.

In the Worker class client, the delegate instance is set to point to the method that will be called when reporting the amount of work done.

Private mWorker As new Worker
'Sets the delegate instance to the method implementation
mWorker.Handler = AddressOf work_WorkDone

The above code uses delegates directly, not the event construct, so neither the AddHandler nor RemoveHandler methods can be used. This exposes only one public variable, so there can be only one method to handle the invocation of the delegate.

Directly using the delegates method eliminates the setting of multiple event handlers for one event source, which would notify all handlers when the event occurs. But an event type can be set as a delegate and use the event-handling mechanism, resulting in cleaner code as follows:

  Public Class Worker
 
    Public Delegate Sub WorkDone(ByVal completedWork As Integer )
    Public Handler As WorkDone
    Public Sub DoWork() 
      For completedWork As Integer = 1 To 10
 
        System.Threading.Thread.Sleep(1000)
        RaiseEvent WorkEvent(completedWork * 10)
        Console.WriteLine(completedWork)
 
      Next 
    End Sub 
  End Class

Custom events in VB.NET 8.0

Custom events provide flexibility and control in creating and managing events. When using custom events, it is the responsibility of the developer to bind and unbind handlers, as well as to specify the actual calls to raise the events. Although this requires a bit more code than the earlier implementations, it provides more control over the handlers and the invocation.

A custom event is defined by using the Custom keyword in front of the event declaration, and by providing the delegate type for the event. The custom event has three sections: The AddHandler section, which is invoked whenever a handler is added using the Handles keyword or the AddHandler method; RemoveHandler section, which is called whenever a handler is removed using the RemoveHandler method; and the RaiseEvent section that will be invoked whenever an event is requested. The developer should write the necessary code in each of these sections to manage the handlers, as well as specify how handlers will be notified when an event is requested.

Below, the Worker class is implemented using the custom event construct in VB.NET 2005.

  Public Class Worker
 
    Public Delegate Sub WorkDone(ByVal completedWork As Integer )
    Private handlers As New ArrayList()
Public Custom Event WorkCompleted As WorkDone
 
      AddHandler (ByVal value As WorkDone)
 
        If handlers.Count <= 5 Then
 
          handlers.Add(value) 
        End If 
      End AddHandler
      RemoveHandler(ByVal value As WorkDone)
        handlers.Remove(value) 
      End RemoveHandler
      RaiseEvent (ByVal completedWork >As Integer)
 
        If completedWork > 50 Then 
          For Each handler As WorkDone In handlers 
            handler.Invoke(completedWork) 
          Next 
        End If 
      End RaiseEvent 
    End Event



Public Sub DoWork()
 
      For completedWork As Integer = 1 To 10 
        System.Threading.Thread.Sleep(1000)
        RaiseEvent WorkCompleted(completedWork * 10)
        Console.WriteLine(completedWork)
 
      Next 
    End Sub 
  End Class

Using custom events enables more control over the handlers. In the above code, for example, there is a condition in the AddHandler section limiting the number of handlers for which events are provided. The RaiseEvent method has been changed to notify the handlers only when the completed Work is more than 50. Another advantage to using custom events is a central unit of code containing all of the handlers of the event within the event construct.

Using RaiseEvent twice, once in the DoWork method and then in the custom event construct, can lead to confusion. RaiseEvent in the DoWork method will raise the event, but the RaiseEvent section in the custom event construct specifies the code to be executed when the event is raised. In this case, all of the handlers are looped through and delegates are invoked.

Events and delegates are important parts of the .NET language. VB.NET 2005 gives developers control and flexibility in handling simple event models and custom events.

Amirthalingam Prasanna

Author profile:

Prasanna is a software engineer, technical author and trainer with many years of development and consulting experience in the software development industry. He is a Microsoft MVP in the Visual developer category, and a MCPD on enterprise application development. He has authored many articles and has worked on content creation for many Microsoft certification exams and courses. He is also a frequent speaker at Microsoft technology conferences and events. You can read his blog at www.prasanna.ws and e-mail him at feedback@prasanna.ws

Search for other articles by Amirthalingam Prasanna

Rate this article:   Avg rating: from a total of 176 votes.


Poor

OK

Good

Great

Must read
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: Good stuff
Posted by: Anonymous (not signed in)
Posted on: Sunday, August 13, 2006 at 8:29 PM
Message: Really helped understand delegates and event handlers in .NET. As an ex VB6'er moving to .NET that's one thing I was having a hard time with.

Subject: Good Job
Posted by: Anonymous (not signed in)
Posted on: Saturday, September 02, 2006 at 3:54 PM
Message: This article is pretty good to understand event handling but I belive, author should explain little more on delegates.

Subject: spot on mate!
Posted by: Anonymous (not signed in)
Posted on: Thursday, September 21, 2006 at 5:10 AM
Message: Is there a performance advantage on using delegates rather than raising events?

Generally should events be used?

Ta.

Percival
pcaburia@cisco.com

Subject: great job
Posted by: Anonymous (not signed in)
Posted on: Saturday, November 04, 2006 at 5:13 AM
Message:
its great post yaa...

janeshh@gmail.com

Subject: Must read!!!
Posted by: Anonymous (not signed in)
Posted on: Sunday, November 26, 2006 at 6:14 PM
Message: ... for sure

Subject: Must read!!!
Posted by: Anonymous (not signed in)
Posted on: Sunday, November 26, 2006 at 7:28 PM
Message: ... for sure

Subject: Nice
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 06, 2006 at 2:52 AM
Message: Nice ,
Any One Must Read This Article

Subject: Must read!!!
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 06, 2006 at 2:53 AM
Message: Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!

Subject: Must read!!!
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 06, 2006 at 2:54 AM
Message: Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!
Must read!!!

Subject: Why an ArrayList?
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 06, 2006 at 4:29 PM
Message: In your example code, you set up the custom event to maintain an ArrayList of handlers for that event. Why not just use Delegate.Combine and Delegate.Remove to maintain the invocation list of the multicast delegate associated with that event? Wouldn't the following work?

Public Delegate Sub MyEventHandler(ByVal sender As Object, ByVal e As EventArgs)
Private m_MyEvent As MyEventHandler
Public Custom Event MyEvent As MyEventHandler
AddHandler(ByVal value As MyEventHandler)
m_MyEvent = DirectCast( _
[Delegate].Combine(m_MyEvent, value), _
MyEventHandler)
End AddHandler

RemoveHandler(ByVal value As MyEventHandler)
m_MyEvent = DirectCast( _
[Delegate].RemoveAll(m_MyEvent, value), _
MyEventHandler)
End RemoveHandler

RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
m_MyEvent.Invoke(sender, e)
End RaiseEvent
End Event

Subject: Why an ArrayList?
Posted by: Anonymous (not signed in)
Posted on: Wednesday, December 06, 2006 at 5:33 PM
Message: In your example code, you set up the custom event to maintain an ArrayList of handlers for that event. Why not just use Delegate.Combine and Delegate.Remove to maintain the invocation list of the multicast delegate associated with that event? Wouldn't the following work?

Public Delegate Sub MyEventHandler(ByVal sender As Object, ByVal e As EventArgs)
Private m_MyEvent As MyEventHandler
Public Custom Event MyEvent As MyEventHandler
AddHandler(ByVal value As MyEventHandler)
m_MyEvent = DirectCast( _
[Delegate].Combine(m_MyEvent, value), _
MyEventHandler)
End AddHandler

RemoveHandler(ByVal value As MyEventHandler)
m_MyEvent = DirectCast( _
[Delegate].RemoveAll(m_MyEvent, value), _
MyEventHandler)
End RemoveHandler

RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
m_MyEvent.Invoke(sender, e)
End RaiseEvent
End Event

Subject: EventArgs
Posted by: Gabe (not signed in)
Posted on: Friday, December 22, 2006 at 1:44 PM
Message: good article, you may want to address when creating events to follow the sender/eventarg standard.

Subject: Nice
Posted by: Anonymous (not signed in)
Posted on: Thursday, March 29, 2007 at 3:26 AM
Message: good article mate i fully understood delegates. Thanks for the help!!

Subject: Indeed Great information
Posted by: Anonymous (not signed in)
Posted on: Thursday, April 19, 2007 at 3:26 PM
Message: I had tough time understanding this... not its pretty simple for me....

I respect this great job of making this concept so simple.....

Subject: Very good but...
Posted by: Anonymous (not signed in)
Posted on: Tuesday, May 01, 2007 at 3:42 PM
Message: I am getting blue squigglies under Handlers.Remove(value), Handlers.Add(value), RaiseEvent() method. Thoughts?

Subject: Very good article.
Posted by: Ather Ali (not signed in)
Posted on: Friday, August 24, 2007 at 9:38 AM
Message: I found it as a very good and will highly recommend for reading. Concrete and to the point stuff is provided into this article.

Subject: Absolutely Good
Posted by: Anirudh (not signed in)
Posted on: Thursday, October 25, 2007 at 10:38 AM
Message: Concept is very good and simple...

Subject: very good
Posted by: Anonymous (not signed in)
Posted on: Tuesday, February 12, 2008 at 12:29 AM
Message: can u pls give more details on delegates

Subject: pls help me
Posted by: T.Srinivasa reddy (not signed in)
Posted on: Thursday, March 06, 2008 at 5:48 AM
Message: i have some doubts.
1. my task is covert to vb6 to vb.net 2005. how to convert.
2. for converting any softwares is there?
3. how to create paint event in vb.net
pls send me answers to my mail
pls help me sir.........
Thanks&Regards
T.Srinivasa Reddy
09970526736
srinivas.reddy@ce-n.com

Subject: nice artical
Posted by: Anonymous (not signed in)
Posted on: Wednesday, March 12, 2008 at 11:11 PM
Message: nice artical , on custom event

Subject: preeety good
Posted by: eunice muriithi (view profile)
Posted on: Tuesday, March 25, 2008 at 6:21 AM
Message: thanks for the easy to follow article

Subject: Thanks!
Posted by: Chris O'Brien (not signed in)
Posted on: Friday, April 18, 2008 at 11:42 AM
Message: I hate being a newbie trying to figure out the basics in a new language. This made it so much easier

Subject: thanks your article.
Posted by: Anonymous (not signed in)
Posted on: Friday, April 25, 2008 at 10:02 AM
Message: thanks your article..
very good.

Subject: Some Typos
Posted by: Wade Walker (not signed in)
Posted on: Wednesday, April 30, 2008 at 2:47 PM
Message: Good article but your code had to be adjusted some to work

Your example code directly above the VisualBasic 8.0 example doesn't work.

And instead of >50, in your 'raise event' example of the last code example, it should be < 50.

Thanks!

Subject: thanks
Posted by: TheLastAnonymous (not signed in)
Posted on: Friday, May 30, 2008 at 6:24 AM
Message: good paper

Subject: thanks
Posted by: anil dere (not signed in)
Posted on: Thursday, June 05, 2008 at 7:09 AM
Message: good code

Subject: hau
Posted by: Anonymous (not signed in)
Posted on: Monday, August 18, 2008 at 2:22 AM
Message: good

 

Top Rated

Acceptance Testing with FitNesse: Multiplicities and Comparisons
 FitNesse is one of the most popular tools for unit testing since it is designed with a Wiki-style... Read more...

Acceptance Testing with FitNesse: Symbols, Variables and Code-behind Styles
 Although FitNesse can be used as a generic automated testing tool for both applications and databases,... Read more...

Building Performance Metrics into ASP.NET MVC Applications
 When you're instrumenting an ASP.NET MVC or Web API application to monitor its performance while it is... Read more...

Acceptance Testing with FitNesse: Documentation and Infrastructure
 FitNesse is a popular general-purpose wiki-based framework for writing acceptance tests for software... Read more...

TortoiseSVN and Subversion Cookbook Part 11: Subversion and Oracle
 It is only recently that the tools have existed to make source-control easy for database developers.... Read more...

Most Viewed

A Complete URL Rewriting Solution for ASP.NET 2.0
 Ever wondered whether it's possible to create neater URLS, free of bulky Query String parameters?... Read more...

Visual Studio Setup - projects and custom actions
 This article describes the kinds of custom actions that can be used in your Visual Studio setup project. Read more...

.NET Application Architecture: the Data Access Layer
 Find out how to design a robust data access layer for your .NET applications. Read more...

Calling Cross Domain Web Services in AJAX
 The latest craze for mashups involves making cross-domain calls to Web Services from APIs made publicly... Read more...

Web Parts in ASP.NET 2.0
 Most Web Parts implementations allow users to create a single portal page where they can personalize... Read more...

Why Join

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.