Events are part of what we call the Callback Mechanism. One way of looking at OOP is by using a communications paradigm. Objects communicate with each other by sending and receiving messages. Messages are received using methods and properties. Messages are sent via callbacks or events. Classes can fire events anytime they want to notify any class that's listening for some action. The class that's listening for the event can then take appropriate action, or do nothing. Thus we can say that we have event senders and event listeners. Another more academic way of saying this is that there are event sources and event sinks . VB provides a very robust event system.
The first and most basic way of creating and using events is as follows :
In the source class, declare the event you wish to use, like this:
Public Class Seinfeld Public Event WeirdThingHappens(ByVal strSomeArg As String) End Class
In the listening class where the source class has been declared using the WithEvents keyword and instantiated , create an event handler, like this:
Private WithEvents mJerry As New Seinfeld() Private Sub SomeWeirdEventHandler(ByVal strSomeArg As String) _ Handles mJerry.WeirdThingHappens MsgBox(StrSomeArg) End Sub
In the source class where you want to fire the event, add code like this:
Public Class Seinfeld Public Event WeirdThingHappens(ByVal strSomeArg As String) Private Sub SomethingWeirdHappens() RaiseEvent WeirdThingHappens("What's up with that? Yada yada yada.") End Sub End Class
A delegate is an object that contains a reference to a procedure. Delegates enable events to be wired at runtime. When we say we wire an event, it means that we connect the event to an event handler. The most basic way to do this at runtime is to use the AddHandler keyword. Suppose we have the same event and source class defined earlier. Suppose also that we do not know what we want the program to do at design time. One of two possible event handlers must be invoked depending on some user input. If the user sets a variable to 1, then one handler is invoked; any other value and a second handler is invoked. At some point in the code, after the user has set the value, you can wire the event on the fly, like this:
Private Sub SetHandler() If intUser = 1 then Addhandler mJerry.WeirdThingHappens, AddressOf HandlerA Else Addhandler mJerry.WeirdThingHappens, AddressOf HandlerB End If End Sub Private Sub HandlerA(ByVal strSomeArg As String) MsgBox(StrSomeArg) End Sub Private Sub HandlerB(ByVal strSomeArg As String) Console.WriteLine(StrSomeArg) End Sub
One of the important items to note in the example is that both event handlers are regular procedures and they both have the same parameter signature as the event itself. These are the requirements of event handlers. You will generate an error if the parameter signatures do not match the signature of the event. Another item to note is the use of the AddressOf operator. This operator returns a delegate to the procedure that follows. As we mentioned earlier, a delegate is similar to a function pointer in C. However, it is a more powerful object if it contains the address of a procedure, and information about the class the procedure belongs to and the parameter signature of the procedure. This enables VB to validate that the delegate actually points to a valid procedure.
VB 6 In VB 6 there was an AddressOf operator as well. This operator was much different though. The VB 6 AddressOf operator returned a pointer to a procedure, and the procedure could only be in a standard module. It was mainly used to provide function pointers to Windows APIs that required callbacks, such as window enumerators and window message functions. In VB .NET it returns a reference type that is an object. The object contains information about the procedure including the class it is in and its parameter signature.
In VB 6 you could only handle events by their predefined procedure name . The event handlers had to be in a class module of some type (class, form, usercontrol, etc). In VB .NET there is no such restriction. Events can be handled anywhere , including modules. (In VB .NET standard modules are classes as well.) In addition, you can wire an event handler to an object that is declared locally within a procedure. This was not possible in VB 6.
There is a lot more to delegates than we have covered here. Delegates can be declared directly and assigned to variables . We will not delve into this now. They are a very powerful feature of VB .NET and have many uses besides handling events. However, these are beyond the scope of this book. Indeed there could be an entire book on delegates and the reflection classes. Perhaps someone will write one someday.