Events and Delegates
An event occurs when an object sends a signal that an action has taken place. The action can be caused by user interaction, such as a button being clicked, or triggered by program logic, such as a timer. The object that raises or triggers the event is the event sender, and the object that receives the event is the event receiver. The event receiver does whatever it must do when that event occurs; however, there's no communication back to the object that triggered the event indicating that it was handled or the result if it was handled. Therefore, the event receiver is always a subroutine and not a function because the return value has no meaning.
A class can define events within the class definition; however, no functional code is associated with the event. Functional code is handled by the event receiver when it receives the event notification.
The issue with events is how two objects communicate with each other and know what information is being sent when an event occurs. Delegates come into play here. A delegate defines a special function pointer template or blueprint that both the sender and receiver use to communicate at the same level. For example, if an event has a String as a parameter, the delegate for that event is declared to have a String as the parameter. Whenever an event handler is assigned to handle that event, it must match the delegate's parameter list and define a String as a parameter. It can't have anything other than the parameters defined by the delegate.
To define a delegate, you use the Delegate keyword. The following shows a delegate that receives Object and System.EventArgs as parameters:Delegate Sub EventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
With a delegate defined, you can declare events that use the delegate as the format of the event notification subroutine. The following Button class shows the declaration of some typical events for a push button using the EventHandler delegate:
Class Button Public Event Click As EventHandler Public Event DoubleClick As EventHandler Public Event RightClick As EventHandler End Class
Although the Button class uses the same delegate for all its events, it could have several delegates and use a different one for each event if appropriate.
To handle the events of an object from within another object, you define the object with a WithEvents variable and Handles clause. For example, the following shows a class with a variable of type Button; the class also defines a subroutine to handle the Click event:
Class Form1 Private WithEvents Button1 As New Button() Protected Sub Button1_Click(sender As Object, _ e As System.EventArgs) Handles Button1.Click ' Place button click code here End Sub End Class
Whenever the user clicks the Button1 object, the Button class, defined in the .NET Framework, has code that recognizes that the user clicked the button and uses the RaiseEvent statement to raise the Click event and signal the Form1 class that the button has been clicked. The Form1 class handles the Button1.Click event and its subroutine, Button1_Click(), which is called when the event is raised. The RaiseEvent keyword is used to trigger an event as follows:RaiseEvent Click( Me, New System.EventArgs() )
The Button1_Click() subroutine has the same parameter list as the delegate EventHandler. This is enforced by the compiler, so the arguments passed with the RaiseEvent statement can be accepted by the event handler.