Delegates and Event Implementation

 <  Day Day Up  >  

Advanced

How events are implemented in Visual Basic .NET using delegates is an advanced topic. It is not necessary to understand the implementation if you only wish to use events or delegates. Readers who are not interested in this topic can feel free to skip to the chapter's conclusion.


Hidden behind the event syntax described in this chapter is a fair amount of plumbing. Events are not as simple as they look ”underneath the covers, an event is really just a delegate. (This is why this chapter covers both events and delegates.) For example, the following code:

 Class Button   Event Moved(ByVal X As Integer, ByVal Y As Integer)   Sub Move(ByVal X As Integer, ByVal Y As Integer)     RaiseEvent Moved(X, Y)   End Sub End Class 

at an implementation level looks more like this.

 Class Button   Public Delegate Sub ClickEventHandler()   Private ClickEvent As ClickEventHandler   Public Sub add_Click(ByVal NewHandler As ClickEventHandler)     ClickEvent = CType(System.Delegate.Combine(ClickEvent, _       NewHandler), ClickEventHandler)   End Sub   Public Sub remove_Click(ByVal OldHandler As ClickEventHandler)     ClickEvent = CType(System.Delegate.Remove(ClickEvent,     OldHandler), _               ClickEventHandler)   End Sub   Public Sub Click()     Dim TempClickDelegate As ClickEventHandler     TempClickDelegate = ClickEvent     If Not TempClickDelegate Is Nothing Then       TempClickDelegate()     End If   End Sub End Class 

It's worthwhile going through this code step-by-step. The first step in declaring an event is to define a delegate that has the same signature as the event. When you are declaring an event, the compiler declares a nested delegate type named XEventHandler for an event named X . It is also possible to use a preexisting delegate type when you are declaring an event by using an alternate event syntax.

 Class Button   Event Click As EventHandler End Class 

In this case, the event does not declare its own delegate type ”instead, it uses the System.EventHandler delegate type as its delegate type. This means it has the same signature as if the declaration had been as follows .

 Class Button   Event Click(ByVal sender As Object, ByVal e As EventArgs) End Class 

Note that the delegate type used in the alternate syntax must be a subroutine ”declaring events with return types is not supported.

The delegate is used to hold references to all the methods that are handling a particular event. When another class wants to handle the Click event, it creates a delegate that refers to its handler and then passes the delegate to the add_Click method. The add_Click method combines the passed-in delegate with the other delegates already handling the event, if any. When another class wants to stop handling the Click event, it creates another delegate that refers to its handler and then passes the delegate to the remove_Click method. The remove_Click method removes the delegate from the list of delegates handling the event.

When a class raises an event, it must first check to make sure that the delegate is not Nothing . If the delegate is Nothing , no one is handling the event and no work needs to be done. If the delegate is not Nothing , the delegate is invoked with the provided parameters. This causes each handler to be called with the specified parameters.

Advanced

The value of ClickEvent is read into a temporary variable before it is invoked, to prevent a race condition in a multithreaded application. If this weren't done, it might be possible for the last handler to be removed from the delegate between the check for Nothing and the delegate being invoked, causing a runtime exception.


This covers the event declaration side, but what of the event handling side? AddHandler and RemoveHandler turn into direct calls to the add and remove methods of the event. But declarative event handling turns out to be quite a bit more complex. For example, the following code:

 Class Form1   Public WithEvents Button1 As Button   Public Sub Button1_Click() Handles Button1.Click     MsgBox("Button1 was clicked!")   End Sub End Class 

at an implementation level looks more like this.

 Class Form1   Private _Button1 As Button   Public Property Button1() As Button     Get       Return _Button1     End Get     Set (ByVal Value As Button)       If Not _Button1 Is Nothing Then         RemoveHandler _Button1.Click, AddressOf Button1_Click       End If       _Button1 = Value       If Not _Button1 Is Nothing Then         AddHandler _Button1.Click, AddressOf Button1_Click       End If     End Set   End Property   Public Sub Button1_Click()     MsgBox("Button1 was clicked!")   End Sub End Class 

At the implementation level, a WithEvents field is a property that knows how to hook up all the event handlers for that field. When a value is assigned to the property, the Set accessor first removes the event handlers from the existing delegate stored in the property. It then changes the value of the property and adds the event handlers to the new instance.

Declaratively handling events in a base class is a little different because there is no field to hook up to. Instead, the instance that raises events is always the instance of the class itself. So the following code:

 Class Base   Public Event Click(ByVal x As Integer, ByVal y As Integer) End Class Class Derived   Inherits Base   Public Sub Clicked(ByVal x As Integer, ByVal y As Integer) _     Handles MyBase.Click     MsgBox("Derived was clicked!")   End Sub End Class 

at an implementation level looks more like this.

 Class Derived   Inherits Base   Public Sub New()     AddHandler Me.Click, AddressOf Me.Clicked   End Sub   Public Sub Clicked(ByVal x As Integer, ByVal y As Integer)     MsgBox("Derived was clicked!")   End Sub End Class 

When the class is constructed , all it needs to do is add a handler to the base event. It never needs to stop handling the event, because that will happen automatically when the class is finalized.

 <  Day Day Up  >  


The Visual Basic .NET Programming Language
The Visual Basic .NET Programming Language
ISBN: 0321169514
EAN: 2147483647
Year: 2004
Pages: 173
Authors: Paul Vick

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net