By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,758 Members | 1,250 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,758 IT Pros & Developers. It's quick & easy.

Delegate et al

P: n/a
Hi,

I am thinking about the delegate mechanism and try to understand it. I
am coming from
C++ and know about callbacks or member callbacks.

In C++ I have this typedef for every class that implements member
callbacks:
typedef bool (__cdecl IEventHandler::*lbEvHandler)(IUnknown* uk);

Each class, that implements such methods, would register these by this
method call:
IDispatcher* disp = getDispatcher();
disp->addEventHandlerFn(this, (lbEvHandler) &MyClass::MyFoo, "MyFoo");

Thus, calling such a method is done by:
IDispatcher* disp = getDispatcher();
disp->dispatch("MyFoo", myParam, &result);

So, my dispatcher knows of all my registered functions and can invoke
it by name.
The second parameter is the functions needed data and the last is for
error handling.

This way I can register a buttons click event to any instance,
supporting that event.

Using delegates, I don't know, how to do similar stuff. Especially, the
AddressOf
mechanism seems to be only for the method, but how about multible
instances of the
same class ?

See the 'this' parameter for the instance, providing that function.

Did AddressOf returns an implicit value for 'this' ?

I need this information, bacause in C++ I store both, object instance
pointer and member
pointer to the function.

Any help ?

Thanks, Lothar

Jul 12 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
>Using delegates, I don't know, how to do similar stuff. Especially, the
AddressOf
mechanism seems to be only for the method, but how about multible
instances of the
same class ?

See the 'this' parameter for the instance, providing that function.

Did AddressOf returns an implicit value for 'this' ?
The default is 'this' (or rather Me in VB) but you can use the syntax

AddressOf someOtherInstance.HandlerMethod

for other objects.
Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Jul 12 '06 #2

P: n/a
Lothar (!!) wrote:
(inline)
Hi,

I am thinking about the delegate mechanism and try to understand it. I
am coming from
C++ and know about callbacks or member callbacks.

In C++ I have this typedef for every class that implements member
callbacks:
typedef bool (__cdecl IEventHandler::*lbEvHandler)(IUnknown* uk);
In VB it would be:

Delegate Function lbEvHandler(Uk As IUnknown) As Boolean

Notice that only the method signature is necessary, not the base class.
In fact any method with this same signature (even shared (static)
methods) regardless of the class where it's implemented is a suitable
lbEventHandler delegate.
Each class, that implements such methods, would register these by this
method call:
IDispatcher* disp = getDispatcher();
disp->addEventHandlerFn(this, (lbEvHandler) &MyClass::MyFoo, "MyFoo");

Thus, calling such a method is done by:
IDispatcher* disp = getDispatcher();
disp->dispatch("MyFoo", myParam, &result);

So, my dispatcher knows of all my registered functions and can invoke
it by name.
The second parameter is the functions needed data and the last is for
error handling.
Delegates have single and multi dispatch built in. When you add a
handler to a delegate, whenever it's Invoke method is called, your
handler will be called also, automagically.

One possible scenario of using delegates is as simple function
pointers. For historical reasons, you pass the address of a method to a
delegate using the AddressOf operator. You execute the actual
'delegated' method by calling the delegate's Invoke method.

Function OnLblEvent(U As IUnknown) AS Boolean
'...
End Function
'...
Dim S As New lbEvHandler(AddressOf OnLblEvent)
'Which is similar to:
Dim R As lbEvHandler = AddressOf OnLblEvent
Dim I As IUnknwon
Dim Result As Boolean = S.Invoke(I)

As you can see, the Invoke method of a given delegate will have the
same signature of the delegate's declaration.
This way I can register a buttons click event to any instance,
supporting that event.
As for events, there are various approaches to add handlers to them.
Suppose you have a Button (OkButton) that raises the event Sub
Click(Sender As Object). One way of adding handlers to this event would
be:

'the following is needed when you use
'the inline Handles clause to automatically
'declare handlers:
Private WithEvents OkButton

Sub OnButtonClick(Sender As Object) _
Handles OkButton.Click
'...
End Sub

Or you could do it dinamically:

AddHandler OkButton.Click, AddressOf OnButtonClick

Or still:

Dim H As ClickEventHandler = AddressOf OnButtonClick
'...
AddHandler OkButton.Click, H

You can add as many handlers as you want to a given event:

AddHandler OkButton.Click AddressOf OnButtonClick
AddHandler OkButton.Click AddressOf ClickHandler
Addhandler OkButton.Click AddressOf AnotherClickHandler
'...

Likewise, you can use a given handler to listen to any number of events
from whatever sources:

For Each C As Control In Controls
If TypeOf C is Button Then
AddHandler C.Click, AddressOf GlobalClickHandler
End If
Next
Using delegates, I don't know, how to do similar stuff. Especially, the
AddressOf
mechanism seems to be only for the method, but how about multible
instances of the
same class ?
I'm not sure if I understand the question. The AddressOf returns a
specific instance of a method, be it a shared (static) or an non-shared
method of a class. I mean, it represents an actual method from a specic
object.

Now, suppose you have many instaces of a given class (Listener), and
all of then wanted to 'listen' to events of a given object (Source),
say, the good old Click event.

To make things clearer, suppose you have a method in some other class
(Dispatcher) which gets a list of listeners that must be attached to
the source event:

Class Listener
Public Sub Click(Sender As Object): end Sub
End Class

Class EventSource
Public Event Click(Sender As Object)
'...
Sub DoIt
'...
RaiseEvent Click(Me) '<-- Keep an eye on here
End If
End Class

Class Dispatcher
Dim mEventSource As New EventSource

Sub AddListeners(List As IEnumerable(Of Listener))
For Each L As Listener In List
AddHandler mEventSource.Click, AddressOf L.Click
Next
End Sub

Sub MeanwhileOnAnotherPlanet
mEventSource.DoIt
End Sub

End Class

When the Source class executes the RaiseEvent action inside the DoIt
method, all event handlers attached to the Click event will be executed
in the order in wich they were registered.
See the 'this' parameter for the instance, providing that function.

Did AddressOf returns an implicit value for 'this' ?

I need this information, bacause in C++ I store both, object instance
pointer and member
pointer to the function.
As you've seen, the AddressOf returns both the Object and method
addresses (the Object will be null for shared methods, I guess), but it
does so implicitly

HTH.

Regards,

Branco.

Jul 12 '06 #3

P: n/a

Branco Medeiros wrote:
Lothar (!!) wrote:
(inline)
Hi,

I am thinking about the delegate mechanism and try to understand it. I
am coming from
C++ and know about callbacks or member callbacks.

In C++ I have this typedef for every class that implements member
callbacks:
typedef bool (__cdecl IEventHandler::*lbEvHandler)(IUnknown* uk);

In VB it would be:

Delegate Function lbEvHandler(Uk As IUnknown) As Boolean

Notice that only the method signature is necessary, not the base class.
In fact any method with this same signature (even shared (static)
methods) regardless of the class where it's implemented is a suitable
lbEventHandler delegate.
Each class, that implements such methods, would register these by this
method call:
IDispatcher* disp = getDispatcher();
disp->addEventHandlerFn(this, (lbEvHandler) &MyClass::MyFoo, "MyFoo");

Thus, calling such a method is done by:
IDispatcher* disp = getDispatcher();
disp->dispatch("MyFoo", myParam, &result);

So, my dispatcher knows of all my registered functions and can invoke
it by name.
The second parameter is the functions needed data and the last is for
error handling.

Delegates have single and multi dispatch built in. When you add a
handler to a delegate, whenever it's Invoke method is called, your
handler will be called also, automagically.

One possible scenario of using delegates is as simple function
pointers. For historical reasons, you pass the address of a method to a
delegate using the AddressOf operator. You execute the actual
'delegated' method by calling the delegate's Invoke method.

Function OnLblEvent(U As IUnknown) AS Boolean
'...
End Function
'...
Dim S As New lbEvHandler(AddressOf OnLblEvent)
'Which is similar to:
Dim R As lbEvHandler = AddressOf OnLblEvent
Dim I As IUnknwon
Dim Result As Boolean = S.Invoke(I)
You only register the function to the handler. (Line 1)

I need to dispatch an event to one S[eventname] in in a list of
multiple S'.
A mapping of ID/EventName to S must be applied (dispatch).

I have the following requirements:

A GUI client get's information, what menu and what entries it has to
build.
This information is passed by strings, because the GUI cannot call
function pointers.
To be prcicely, it is WinDev and our middle layer is .NET Assemblies.

' A plugin's code

Function OnMenuOpenFileEvent(U As IUnknown) AS Boolean
'...
End Function

Function OnMenuNewFileEvent(U As IUnknown) AS Boolean
'...
End Function

Function OnMenuSaveFileEvent(U As IUnknown) AS Boolean
'...
End Function

Sub Init()

Dim evM as EventManager = GetGlobalEventManager() ' Singleton
Dim appM as ApplicationManager = GetGlobalApplicationManager() '
Singleton
Dim disp as Dispatcher = GetGlobalDispatcher() ' Singleton
Dim evID as Integer

evM.registerHandler("OnMenuOpenFileEvent", evID) ' evID parameter
gets the id (ByRef)
disp.registerHandlerMethod("OnMenuOpenFileEvent", AddressOf
OnMenuOpenFileEvent)
or
disp.registerHandlerMethod(evID, AddressOf OnMenuOpenFileEvent)
to avoid multiple eventID lookups (by invoking
EventManager.resolveName("OnMenuOpenFileEvent") inside of the
dispatcher).

evM.registerHandler("OnMenuNewFileEvent", evID) ' evID parameter
gets the id (ByRef)
disp.registerHandlerMethod("OnMenuNewFileEvent", AddressOf
OnMenuNewFileEvent)

evM.registerHandler("OnMenuSaveFileEvent", evID) ' evID parameter
gets the id (ByRef)
disp.registerHandlerMethod("OnMenuSaveFileEvent", AddressOf
OnMenuSaveFileEvent)

appM.AddMenu("&File")
appM.AddMenuEntry("&File", "&New", "OnMenuNewFileEvent")
appM.AddMenuEntry("&File", "&Open", "OnMenuOpenFileEvent")
appM.AddMenuEntry("&File", "&Save", "OnMenuSaveFileEvent")
End Sub

The handling of information passing (AddMenu*) to the GUI is not shown
here.
Maybe it will be message passing.

As you see, the GUI did not directly expose it's menu Click's, because
it is not VB,
nor any .NET language (but can use .NET).

So I must use identifers like strings, or to fasten it, their
registered ID's.

The GUI could use .NET assemblies, thus it will have access to the
dispatcher et al.
Given, the GUI controls are proper set up to route its events to a
WinDev specific
handler (catch all), it is capable to build a bunch of information, the
handler needs and
pass it with the following code to the handler in behind:

myParameter is IParameter object dynamic // WinDev code !
myParameter = getParameterInstance() // WinDev code !

myResult is IParameter object dynamic // WinDev code !
myResult = getParameterInstance() // WinDev code !

// Fill the parameter with the required data (application specific)
// What to fill was given to the GUI with the handler to be 'called',
eg
// 'Fill with control 'Name', 'SureName', 'Age' ...
// This is very generic and highly dynamic.

MyParameter.addParameter('Name', {'Name'} .. Value) // WinDev code !

disp.dispatch(event.id, myParameter, myResult) // WinDev code !
AddHandler OkButton.Click AddressOf OnButtonClick
AddHandler OkButton.Click AddressOf ClickHandler
Addhandler OkButton.Click AddressOf AnotherClickHandler
Direct access to the control is impossible. Control is in GUI and
handler in plugin.
'...

Likewise, you can use a given handler to listen to any number of events
from whatever sources:

For Each C As Control In Controls
If TypeOf C is Button Then
AddHandler C.Click, AddressOf GlobalClickHandler
End If
Next
Using delegates, I don't know, how to do similar stuff. Especially, the
AddressOf
mechanism seems to be only for the method, but how about multible
instances of the
same class ?

I'm not sure if I understand the question. The AddressOf returns a
specific instance of a method, be it a shared (static) or an non-shared
method of a class. I mean, it represents an actual method from a specic
object.
One navigation toolbar with buttons for 'First', 'Previous', 'Next' and
'Last' and multiple
data windows with their handlers. The GUI part of the data window is
built up upon
information from the middle layer. The handlers are specific to the
'bussiness' object.

On C++ I have solved this, by prepending the address od 'this' as
string to the handler
name. This is not yet one button to many handlers (one per active
window), but it should
be. The dispatcher may not find the eventhandler by searching for
'OnNext', but the GUI
may provide information, such as window name. Thus this could be
prepended and also
the bussiness logic, that requests for a data window may provide a
window name, if
multible windows are needed.

Maybe the bussiness logic registers generic handlers for 'OnFirst', ...
and do
subdispatching like this:

if (!disp.dispatch("OnFirst", ...)) // If a generic handler is
registered
// Fallback to new approach
disp.dispatch("current window's name, that who lost the focus to
the toolbar" & "OnFirst", ...)

I think the Toolbar for data navigation is a good example.

/---Handler for DataWindow1
Toolbar ---<
\---Handler for DataWindow2

Actually, this would by a candidat of implementation for my C++
project, but also for
this one.

Thus only the real listener of such events gets informed.
And no event handler has to be re-registered at window focus issues.
>
Now, suppose you have many instaces of a given class (Listener), and
all of then wanted to 'listen' to events of a given object (Source),
say, the good old Click event.
Doing this with the dispatcher, I must implement a registerListener
method.
I think, that is not required yet.
>
To make things clearer, suppose you have a method in some other class
(Dispatcher) which gets a list of listeners that must be attached to
the source event:

Class Listener
Public Sub Click(Sender As Object): end Sub
End Class

Class EventSource
Public Event Click(Sender As Object)
'...
Sub DoIt
'...
RaiseEvent Click(Me) '<-- Keep an eye on here
End If
End Class

Class Dispatcher
Dim mEventSource As New EventSource

Sub AddListeners(List As IEnumerable(Of Listener))
For Each L As Listener In List
AddHandler mEventSource.Click, AddressOf L.Click
Next
End Sub

Sub MeanwhileOnAnotherPlanet
mEventSource.DoIt
End Sub

End Class
Maybe I use this sample for the listener or observer pattern.
When the Source class executes the RaiseEvent action inside the DoIt
method, all event handlers attached to the Click event will be executed
in the order in wich they were registered.
See the 'this' parameter for the instance, providing that function.

Did AddressOf returns an implicit value for 'this' ?

I need this information, bacause in C++ I store both, object instance
pointer and member
pointer to the function.

As you've seen, the AddressOf returns both the Object and method
addresses (the Object will be null for shared methods, I guess), but it
does so implicitly
The main issues may be, that I have no direct access from the event
source to the
event target. Using a dispatching mechanism with unique ID's per
application instance,
it would be possible to route an event to it's target.

It's a little more than dynamically creating delegates :-(

It has helped :-)

Regards

Lothar

Jul 13 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.