Home

Delegates and Events

 

Delegates Fundamentals

 

Introduction

As done when you declare a variable, when you create and call a procedure, it uses a section of memory of the computer. This section is its address. You can access that area of memory to get to the procedure. Or, you can declare a variable that would be used to access the memory used by the procedure.

A function pointer is a special type of variable that is used to access a function using its address. To support function pointers, the .NET Framework provides the concept of delegates. A delegate is not a real function. It provides a syntax for a function that it would be associated with.

Creating a Delegate

Before using a delegate, you must create it or you can use one of the built-in delegates of the .NET Framework. The basic formula to create a delegate is:

[modifier] Delegate Sub/Function Name (parameter(s)) As ReturnType

The modifier factor can be Public, Private, or Friend. This is followed by either the Delegate Sub or the Delegate Function expression.

A delegate must have a name: The Name factor of this formula. The name follows the rules we have been observing for valid names of the Visual Basic language.

Because a delegate is some type of a template for a procedure, you must use parentheses. If this procedure will not take any argument, you can leave the parentheses empty.

If the delegate will be associated with a sub-procedure, there is no return type. Here is an example:

Module Exercise

    Delegate Sub Messenger()

End Module

If the delegate is a function-type, you must specify a ReturnType. This can be any of the data types we have used so far, or it can be a class.

If you create a procedure that would be associated with a delegate, you can also define it as Shared.

Associating a Delegate to a Procedure

Before using a delegate, you must create a procedure it will be associated with. The procedure must use the same syntax as the delegate:

  • If using a sub-procedure, both must be created as sub-procedures
  • If there is no argument, none of them can take an argument

Here is an example:

Module Exercise
    Delegate Sub Messenger()

    Private Sub ShowMessage()
        MsgBox("Main message")
    End Sub

End Module

Getting the Address of a Procedure

To associate a procedure to a delegate, you must assign the address of the procedure to a variable of the delegate. This means that you must first declare a variable for the delegate.

To assist you with getting the address of a procedure, the Visual Basic language provides the AddressOf operator. To use it, type it followed by the name of the procedure that implements the delegate. Assign that expression to the variable declared from the delegate. Here is an example:

Module Exercise
    Delegate Sub Messenger()

    Private Sub ShowMessage()
        MsgBox("Main message")
    End Sub

    Public Function Main() As Integer
        Dim Mess As Messenger

        Mess = AddressOf ShowMessage

        Return 0
    End Function

End Module

After assigning the address of the procedure to the delegate's variable, you can call the delegate as if it were a procedure. Here is an example:

Module Exercise
    Delegate Sub Messenger()

    Private Sub ShowMessage()
        MsgBox("Main message")
    End Sub

    Public Function Main() As Integer
        Dim Mess As Messenger

        Mess = AddressOf ShowMessage
        Mess()

        Return 0
    End Function

End Module

In our example, we used a sub-procedure. In the same way, if necessary, you can create a delegate as a function. In this case, you would define a function to associate to that delegate. Then, you can use the same techniques we followed to associate them.

Delegates and Classes

When it comes to delegates, not only can you use a normal procedure, you can use the method of a class to associate to a delegate. You can start by creating the class and the necessary method. Here is an example:

Module Exercise

    Private Class Example
        Public Sub Welcome()
            MsgBox("A delegate with class")
        End Sub
    End Class

End Module

Of course, before using the delegate, you must declare it. This is done exactly as previously. The delegate must be of the same type as the method (sub-procedure or function).

Before associating the delegate to the intended method, declare a variable for it. Also declare a variable for the class. To associate the method to the delegate, get the address of the method, through its object, and assign it to the variable of the delegate. Once you have done this, you can call the delegate's variable as if it were a procedure. Here is an example:

Module Exercise

    Delegate Sub Simple()

    Private Class Example
        Public Sub Welcome()
            MsgBox("A delegate with class")
        End Sub
    End Class

    Public Function Main() As Integer
        Dim Simplicity As Simple
        Dim Exo As Example = New Example

        Simplicity = AddressOf Exo.Welcome
        Simplicity()

        Return 0
    End Function

End Module

A delegate is actually a class. The class is named Delegate. Based on this, whenever you create a delegate, the name you give it is considered an object. That is, the name you give to the delegate becomes an object of type Delegate. Based on the characteristics of classes, that delegate object automatically becomes equipped with methods.

Delegates and Arguments

 

Introduction

If you want to associate a procedure that takes arguments to a delegate, when declaring the delegate, provide the necessary argument(s) in its parentheses. Here is an example of a delegate that takes two arguments (and returns a value):

Module Exercise

    Delegate Function Multiplication(ByVal value As Double) As Double

End Module

When defining the associated procedure, besides returning the same type of value, make sure that the procedure takes the same number of arguments. Here is an example:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Delegate Function Multiplication(ByVal value As Double) As Double

    Public Function Area(ByVal Side As Double) As Double
        Return 6 * Side * Side
    End Function

End Module

To associate the procedure, declare a variable of the type of delegate and access the name of the procedure using the AddressOf operator. Here is an example:

Module Exercise
    Delegate Function Multiplication(ByVal value As Double) As Double

    Public Function Area(ByVal Side As Double) As Double
        Return 6 * Side * Side
    End Function

    Public Function Main() As Integer

        Dim AreaDefinition As Multiplication = New Multiplication(AddressOf Area)

        Return 0
    End Function

End Module

To assist you with accessing a delegate, the Delegate class is equipped with a method named Invoke. Therefore, to associate a method to a delegate, call this method on the variable of the delegate. The syntax of the Invoke() method is:

Public Function Invoke(method As Delegate) As Object

Here is an example:

Module Exercise
    Delegate Function Multiplication(ByVal value As Double) As Double

    Public Function Area(ByVal Side As Double) As Double
        Return 6 * Side * Side
    End Function

    Public Function Volume(ByVal Side As Double) As Double
        Return Side * Side * Side
    End Function

    Public Function Main() As Integer

        Dim Side As Double = 46.95
        Dim AreaDefinition As Multiplication
        Dim VolDefinition As Multiplication

        AreaDefinition = New Multiplication(AddressOf Area)
        VolDefinition = New Multiplication(AddressOf Volume)

        MsgBox("Cube Calculation" & vbCrLf & _
               "Side: " & vbTab & CStr(Side) & vbCrLf & _
               "Area: " & vbTab & CStr(AreaDefinition.Invoke(Side)) & vbCrLf & _
               "Volume: " & vbTab & CStr(VolDefinition.Invoke(Side)))

        Return 0
    End Function

End Module

A Delegate Passed as Argument

Using delegates, a procedure can be indirectly passed as argument to another procedure. To proceed, first declare the necessary delegate. Here is a example of such a delegate:

Module Exercise

    Delegate Function Squared(ByVal value As Double) As Double

End Module

A delegate can be passed as argument to a procedure. Such an argument would be used as if it were a procedure itself. This means that, when accessed in the body of the procedure, the name of the delegate must be accompanied by parentheses and if the delegate takes an argument or arguments, the argument(s) must be provided in the parentheses of the called delegate. Here is an example:

Module Exercise
    Private Radius As Double
    Delegate Function Squared(ByVal value As Double) As Double

    Public Function Area(ByVal sqd As Squared) As Double
        Return sqd(Radius) * Math.PI
    End Function
End Module

After declaring a delegate, remember to define a procedure that implements the needed behavior of that delegate. Once the procedure is ready, to associate it to a delegate, declare a variable of the type of the delegate using the New operator. In the parentheses of the constructor, access the name of the associated procedure using the AddressOf operator. To access the delegate, call the Invoke() method. Here is an example:

Module Exercise
    Private Radius As Double
    Delegate Function Squared(ByVal value As Double) As Double

    Public Function Area(ByVal sqd As Squared) As Double
        Return sqd(Radius) * Math.PI
    End Function

    Public Function ValueTimesValue(ByVal value As Double) As Double
        Return value * value
    End Function

    Public Function Main() As Integer

        Dim Side As Double = 46.95
        Dim AreaDefinition As Squared

        AreaDefinition = New Squared(AddressOf ValueTimesValue)

        MsgBox("Circle Calculation" & vbCrLf & _
               "Side: " & vbTab & CStr(Side) & vbCrLf & _
               "Area: " & vbTab & CStr(AreaDefinition.Invoke(Side)))

        Return 0
    End Function

End Module
 

 

 

Events

 

Introduction

In a typical application, every class is mostly meant to interact with others, either to request values and methods of the other classes or to provide other classes with some values or a behavior they need. When a class A requests a value or service from another class B, class A is referred to as a client of class B. This relationship is important not simply because it establishes a relationship between both classes but also because class B should be ready to provide the value or behavior that a client needs at a certain time.

While a class B is asked to provide some values to, or perform some assignment(s) for, another class A, many things would happen. In fact, there is an order that the actions should follow. For example, during the lifetime of a program, that is, while a program is running, a class may be holding a value it can provide to its client but at another time, that value may not be available anymore, for any reason; nothing strange, this is just the ways it happens. Because different things can happen to a class B while a program is running, and because only class B would be aware of these, it must be able to signal to the other classes when there is a change. This is the basis of events: An event is an action that occurs on an object and affects it in a way that its clients must be made aware of. 

Event Creation

An event is declared like a pseudo-procedure. To actually declare an event, you use the Event keyword with the following formula:

[modifier] Event Name(Argument)

The modifier can be Public, Private, Protected, or Friend. The Event keyword is required. It is followed by a name for the event. If the event has arguments, enter them in its parentheses.

Here is an example that declares an event:

Module Exercise

    Private Event Evidence()

End Module

Raising an Event

To use an event, the object that causes it must initiate it. When this happens, the object is said to raise the event. To assist you with this, the Visual Basic language provides the RaiseEvent operator. To use it, the formula to follow is:

RaiseEvent EventName(Argument(s))

You start with the RaiseEvent keyword followed by the name of the event you would have declared previously. The name of the event is followed by parentheses. Here is an example:

Module Exercise
    Private Event Evidence()

    Public Function Main() As Integer
        RaiseEvent Evidence()

        Return 0
    End Function

End Module

Events and Delegates

In reality, an event is something that happens to an object in response to a change in behavior. To possible, an event uses a behavior implemented by a delegate. This means that you must first create the delegate. Once the delegate and the event have been declared, you can hook up the delegate to the event. Then when the appropriate action occurs, the event fires. At that time, the procedure that implements the delegate runs.

Before using an event, you must specify the procedure that will carry the event. This procedure is referred to as a handler. To implement this behavior, the event must return a value, and that value must be the delegate that implements the desired behavior. Obviously you must first have created a procedure. Here is an example:

Module Exercise

    Private Sub ShowMessage()
        MsgBox("Get the necessary message")
    End Sub

End Module

To add a handler to the program, you use the AddHandler operator with the following formula:

AddHandler EventName, AddressOf Procedure

The AddHandler and the AddressOf operators are required. The EventName placeholder is used to specify the name of the event that is being dealt with. The Procedure factor is the name of the procedure that will implement the event. Here is an example:

Module Exercise
    Delegate Sub Messenger()
    Private Event Evidence As Messenger

    Private Sub ShowMessage()
        MsgBox("Get the necessary message")
    End Sub

    Public Function Main() As Integer
        AddHandler Evidence, AddressOf ShowMessage

        Return 0
    End Function

End Module

Raising an Event

After adding a handler to the event, it is ready but you must launch its action. To do this, you can use the RaiseEvent operator with the following formula:

RaiseEvent EventName()

The RaiseEvent operator is required. The EventName placeholder is used to specify the name of the event, and it must be followed by parentheses. Here is an example:

Module Exercise
    Delegate Sub Messenger()
    Private Event Evidence As Messenger

    Private Sub ShowMessage()
        MsgBox("Get the necessary message")
    End Sub

    Public Function Main() As Integer
        AddHandler Evidence, AddressOf ShowMessage

        RaiseEvent Evidence()
        Return 0
    End Function

End Module

A Parameterized Event

The event we used in the previous sections did not take any argument. Just like a delegate, an event can take an argument. The primary rule to follow is that both its delegate and the procedure associated with it must take the same type of event. The second rule is that, when raising the event, you must pass an appropriate event to it. Here is an example:

Module Exercise
    Delegate Sub Messenger(ByVal Msg As String)
    Private Event Evidence As Messenger

    Private Sub ShowMessage(ByVal ToShow As String)
        MsgBox(ToShow)
    End Sub

    Public Function Main() As Integer
        AddHandler Evidence, AddressOf ShowMessage

        RaiseEvent Evidence("Is this the last thing to do?")
        Return 0
    End Function

End Module

Just like an event can take an argument, it can also take more than one argument. The primary rules are the same as those for a single parameter. You just have to remember that you are dealing with more than one argument. Here is an example:

Module Exercise
    Delegate Sub Messenger(ByVal Originator As String, ByVal Msg As String)
    Private Event Evidence As Messenger

    Private Sub ShowMessage(ByVal Sender As String, ByVal ToShow As String)
        MsgBox(Sender & ": " & ToShow)
    End Sub

    Public Function Main() As Integer
        AddHandler Evidence, AddressOf ShowMessage

        RaiseEvent Evidence("Message form the Accounting Department", _
                            "Remember to do your time sheet")
        Return 0
    End Function

End Module

Instead of a parameter of a primitive type, you can create an event that takes a class as argument.

 
 
   
 

Previous Copyright © 2009-2016, FunctionX, Inc. Next