Matching Event Handlers in an Interface

C

Charles Law

Mr "yEaH rIgHt" posted the following link about a week ago in answer to my
question about removing event handlers.

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the pattern
OnXXXX given the sender. It loops through the sender events and tries to get
methods from the receiver that match the pattern. For each one it finds it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't have a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged, but
this also works with the technique above.

The problem arises where my sender has two values that can change. In this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got this far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text? Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Could someone have a look at this please. It seems to me that it should be
possible to get a list of handlers for an event and then remove any handler
that is in a given object. I just can't figure out how to do it.

Anyone?

Charles


Charles Law said:
Mr "yEaH rIgHt" posted the following link about a week ago in answer to my
question about removing event handlers.

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the pattern
OnXXXX given the sender. It loops through the sender events and tries to get
methods from the receiver that match the pattern. For each one it finds it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't have a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged, but
this also works with the technique above.

The problem arises where my sender has two values that can change. In this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got this far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text? Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.

http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp

Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay


Charles Law said:
Mr "yEaH rIgHt" posted the following link about a week ago in answer to my
question about removing event handlers.

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the pattern
OnXXXX given the sender. It loops through the sender events and tries to get
methods from the receiver that match the pattern. For each one it finds it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't have a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged, but
this also works with the technique above.

The problem arises where my sender has two values that can change. In this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got this far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text? Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Hi Jay

Yes, I think that one of those will allow me to test for equality with the
receiver. My first hurdle, though is this line:
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill down
to the invocation list. The Item member seems to need a key in the shape of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


Jay B. Harlow said:
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.

http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp

Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay


Charles Law said:
Mr "yEaH rIgHt" posted the following link about a week ago in answer to my
question about removing event handlers.


Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the pattern
OnXXXX given the sender. It loops through the sender events and tries to get
methods from the receiver that match the pattern. For each one it finds it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't
have
a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged, but
this also works with the technique above.

The problem arises where my sender has two values that can change. In this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got this far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text? Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
A specific hidden field that the designer of the class supplied when they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you are
using the Events collection you should know what that key is. In that you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Charles Law said:
Hi Jay

Yes, I think that one of those will allow me to test for equality with the
receiver. My first hurdle, though is this line:
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill down
to the invocation list. The Item member seems to need a key in the shape of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


Jay B. Harlow said:
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay
to
my to
get
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't
have
a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged, but
this also works with the technique above.

The problem arises where my sender has two values that can change. In this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got
this
far
<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text? Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Jay

I did see once where New Object was used for adding keys, but, as you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is for user use
only. I had expected that the 'framework' would have a method - that I could
get access to - that allowed me to see all the handlers/delegates to be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of delegates that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.

Charles


Jay B. Harlow said:
Charles,
A specific hidden field that the designer of the class supplied when they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you are
using the Events collection you should know what that key is. In that you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Charles Law said:
Hi Jay

Yes, I think that one of those will allow me to test for equality with the
receiver. My first hurdle, though is this line:
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill down
to the invocation list. The Item member seems to need a key in the shape of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
tries
to
get
methods from the receiver that match the pattern. For each one it
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't have
a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two
similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could
easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method
MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values that can change.
In
this
case it can raise two events: Value1Changed and Value2Changed. My receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged, because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as
before,
but for each one I want to get the invocation list, and see if my receiver
is in it. Only if it is do I want to remove the handler. I have got this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles
sender.Events is totally different then Delegate.GetInvocationList.

Delegate.GetInvocationList is how you see all the handlers to be called for
an event.

sender.Events is all the invocationlists for all the events on a component,
if you designed your component to be used that way. (read its a C# thing).
Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

Hope this helps
Jay

Charles Law said:
Jay

I did see once where New Object was used for adding keys, but, as you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is for user use
only. I had expected that the 'framework' would have a method - that I could
get access to - that allowed me to see all the handlers/delegates to be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of delegates that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.

Charles


Jay B. Harlow said:
Charles,
A specific hidden field that the designer of the class supplied when they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you are
using the Events collection you should know what that key is. In that you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Charles Law said:
Hi Jay

Yes, I think that one of those will allow me to test for equality with the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill down
to the invocation list. The Item member seems to need a key in the
shape
of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay


Mr "yEaH rIgHt" posted the following link about a week ago in
answer
to
my
question about removing event handlers.

http://www.vbinfozine.com/t_bindevt.shtml

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the
pattern
OnXXXX given the sender. It loops through the sender events and
tries
to
get
methods from the receiver that match the pattern. For each one it finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't
have
a
straight forward mapping. For example, although I could easily use this
pattern in many cases, there are situations where the sender has two
similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver could
easily
have a method OnValueChanged that could be linked up using the technique
above. As it happens, my receiver has a method MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values that can change. In
this
case it can raise two events: Value1Changed and Value2Changed. My
receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged,
because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events, as
before,
but for each one I want to get the invocation list, and see if my
receiver
is in it. Only if it is do I want to remove the handler. I have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Jay
sender.Events is totally different then Delegate.GetInvocationList.

I didn't mean to suggest that I thought these were the same. Rather than get
bogged down in (perhaps) my misunderstanding, I will state my aim in PDL

For each event that can be raised by an object (sender)
For each event handler currently attached for the given event
If given event handler is on known target (receiver)
Remove handler
End if
Next event handler
Next event

I don't know how to state it any better than that.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

I can't tell if it is an empty list because there is no member for
retrieving the length, and none for indexing either.

Thanks for your continued help.

Charles


Jay B. Harlow said:
Charles
sender.Events is totally different then Delegate.GetInvocationList.

Delegate.GetInvocationList is how you see all the handlers to be called for
an event.

sender.Events is all the invocationlists for all the events on a component,
if you designed your component to be used that way. (read its a C# thing).
Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

Hope this helps
Jay

Charles Law said:
Jay

I did see once where New Object was used for adding keys, but, as you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is for user use
only. I had expected that the 'framework' would have a method - that I could
get access to - that allowed me to see all the handlers/delegates to be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of delegates that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.

Charles


Charles,
A specific hidden field that the designer of the class supplied when they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you are
using the Events collection you should know what that key is. In that you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for equality
with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to
drill
down
to the invocation list. The Item member seems to need a key in the shape
of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
change.
In
events,
as
before,
but for each one I want to get the invocation list, and see if my
receiver
is in it. Only if it is do I want to remove the handler. I have got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
I didn't mean to suggest that I thought these were the same. Rather than get
bogged down in (perhaps) my misunderstanding, I will state my aim in PDL

For each event that can be raised by an object (sender)
Unfortunately I believe you will need to enable the "Option Psychic On"
option, As sender.Events is a secure door, you can only get out what you
know you put in. Which is part of the entire point behind Encapsulation. The
object protects the information that it knows, you need to ask the object
itself for details, if it decides those details are too important not to
share, well its protecting your from yourself...

I can't tell if it is an empty list because there is no member for
retrieving the length, and none for indexing either.
I thought I saw that EventHandlerList implemented IEnumerable, you are
correct it doesn't, so obviously you cannot use it for what you want.


Hope this helps
Jay


Charles Law said:
Jay
sender.Events is totally different then Delegate.GetInvocationList.

I didn't mean to suggest that I thought these were the same. Rather than get
bogged down in (perhaps) my misunderstanding, I will state my aim in PDL

For each event that can be raised by an object (sender)
For each event handler currently attached for the given event
If given event handler is on known target (receiver)
Remove handler
End if
Next event handler
Next event

I don't know how to state it any better than that.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

I can't tell if it is an empty list because there is no member for
retrieving the length, and none for indexing either.

Thanks for your continued help.

Charles


Jay B. Harlow said:
Charles
sender.Events is totally different then Delegate.GetInvocationList.

Delegate.GetInvocationList is how you see all the handlers to be called for
an event.

sender.Events is all the invocationlists for all the events on a component,
if you designed your component to be used that way. (read its a C# thing).
Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

Hope this helps
Jay

Charles Law said:
Jay

I did see once where New Object was used for adding keys, but, as you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is for
user
use
only. I had expected that the 'framework' would have a method - that I could
get access to - that allowed me to see all the handlers/delegates to be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of delegates that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have only
called AddHandler to add a handler for an event.

Charles


Charles,
A specific hidden field that the designer of the class supplied when they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you are
using the Events collection you should know what that key is. In
that
you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for equality with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill
down
to the invocation list. The Item member seems to need a key in the shape
of
an object, but what key should I use? I have searched and searched but
cannot find an example of this anywhere. Can you think what might work?

Thanks.

Charles


message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available
on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay


Mr "yEaH rIgHt" posted the following link about a week ago in answer
to
my
question about removing event handlers.

http://www.vbinfozine.com/t_bindevt.shtml

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match the
pattern
OnXXXX given the sender. It loops through the sender events and
tries
to
get
methods from the receiver that match the pattern. For each one it
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I don't
have
a
straight forward mapping. For example, although I could easily use
this
pattern in many cases, there are situations where the sender
has
two
similar
events, only one of which a particular receiver is going to service.

Let's say that my sender has an event ValueChanged. My receiver
could
easily
have a method OnValueChanged that could be linked up using the
technique
above. As it happens, my receiver has a method
MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values that can change.
In
this
case it can raise two events: Value1Changed and Value2Changed. My
receiver
only services one of these, and which one is determined at runtime.
Therefore, the receiver still has a method MyControl_ValueChanged,
because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform the
event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's
events,
as
before,
but for each one I want to get the invocation list, and see if my
receiver
is in it. Only if it is do I want to remove the handler. I
have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Jay

Perhaps we can approach this in another way. I have repeated my original
code below. If I don't use sender.Events - as you have explained why - is
there a way to create a delegate from ei (an EventInfo object)?

If I could create such a delegate (dlgt) , then I could use
dlgt.GetInvocationList() instead, and I would be well on my way.

What do you think?

Charles

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver As
Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As System.Delegate

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()
' For each event that the sender can raise, get the invocation list
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

For Each dlgt As System.Delegate In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt
Next ei

End Sub
</code>


Jay B. Harlow said:
Charles,
I didn't mean to suggest that I thought these were the same. Rather than get
bogged down in (perhaps) my misunderstanding, I will state my aim in PDL

For each event that can be raised by an object (sender)
Unfortunately I believe you will need to enable the "Option Psychic On"
option, As sender.Events is a secure door, you can only get out what you
know you put in. Which is part of the entire point behind Encapsulation. The
object protects the information that it knows, you need to ask the object
itself for details, if it decides those details are too important not to
share, well its protecting your from yourself...

I can't tell if it is an empty list because there is no member for
retrieving the length, and none for indexing either.
I thought I saw that EventHandlerList implemented IEnumerable, you are
correct it doesn't, so obviously you cannot use it for what you want.


Hope this helps
Jay


Charles Law said:
Jay
sender.Events is totally different then Delegate.GetInvocationList.

I didn't mean to suggest that I thought these were the same. Rather than get
bogged down in (perhaps) my misunderstanding, I will state my aim in PDL

For each event that can be raised by an object (sender)
For each event handler currently attached for the given event
If given event handler is on known target (receiver)
Remove handler
End if
Next event handler
Next event

I don't know how to state it any better than that.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

I can't tell if it is an empty list because there is no member for
retrieving the length, and none for indexing either.

Thanks for your continued help.

Charles


Charles
sender.Events is totally different then Delegate.GetInvocationList.

Delegate.GetInvocationList is how you see all the handlers to be
called
for
an event.

sender.Events is all the invocationlists for all the events on a component,
if you designed your component to be used that way. (read its a C# thing).

Incidentally, sender.Events is *not* nothing in my project, and I have
only
called AddHandler to add a handler for an event.
As I stated, I would expect it to be Nothing or an empty list, is it an
empty list?

Hope this helps
Jay

Jay

I did see once where New Object was used for adding keys, but, as you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is for user
use
only. I had expected that the 'framework' would have a method - that I
could
get access to - that allowed me to see all the handlers/delegates to be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of
delegates
that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have
only
called AddHandler to add a handler for an event.

Charles


Charles,
A specific hidden field that the designer of the class supplied when
they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty
list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If
you
are
using the Events collection you should know what that key is. In that
you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for
equality
with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to drill
down
to the invocation list. The Item member seems to need a key in the
shape
of
an object, but what key should I use? I have searched and
searched
but
cannot find an example of this anywhere. Can you think what might
work?

Thanks.

Charles


message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate Method
properties. The System.Delegate.Equals method may or may not help.

Hope this helps
Jay


Mr "yEaH rIgHt" posted the following link about a week ago in
answer
to
my
question about removing event handlers.

http://www.vbinfozine.com/t_bindevt.shtml

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that
match
the
pattern
OnXXXX given the sender. It loops through the sender events and
tries
to
get
methods from the receiver that match the pattern. For each
one
it
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping, but I
don't
have
a
straight forward mapping. For example, although I could
easily
use
this
pattern in many cases, there are situations where the sender has
two
similar
events, only one of which a particular receiver is going to
service.

Let's say that my sender has an event ValueChanged. My receiver
could
easily
have a method OnValueChanged that could be linked up using the
technique
above. As it happens, my receiver has a method
MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values that can change.
In
this
case it can raise two events: Value1Changed and
Value2Changed.
My
receiver
only services one of these, and which one is determined at
runtime.
Therefore, the receiver still has a method MyControl_ValueChanged,
because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to
transform
the
event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's events,
as
before,
but for each one I want to get the invocation list, and see
if
my
receiver
is in it. Only if it is do I want to remove the handler. I have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
You would need to get at the underlying field that is used as the backing
store for the Event. Or know the magic key to the Events property.

Remember that an Event simply encapsulates a Delegate Field, similar to how
a Property encapsulates other fields.

For example in VB.NET the Changed Event has a ChangeEvent delegate field on
the class.

Just as a Property does not need to be implemented in terms of an actual
field, an Event (in C#) does not need to be implemented in terms of a
Delegate Field. In C# the delegates can be stored in the Events property (an
EventHandlerList class). VB.NET currently does not support the Events
property.

Hope this helps
Jay


Charles Law said:
Jay

Perhaps we can approach this in another way. I have repeated my original
code below. If I don't use sender.Events - as you have explained why - is
there a way to create a delegate from ei (an EventInfo object)?

If I could create such a delegate (dlgt) , then I could use
dlgt.GetInvocationList() instead, and I would be well on my way.

What do you think?

Charles

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver As
Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As System.Delegate

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()
' For each event that the sender can raise, get the invocation list
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

For Each dlgt As System.Delegate In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt
Next ei

End Sub
</code>


Jay B. Harlow said:
Charles, than
get
Unfortunately I believe you will need to enable the "Option Psychic On"
option, As sender.Events is a secure door, you can only get out what you
know you put in. Which is part of the entire point behind Encapsulation. The
object protects the information that it knows, you need to ask the object
itself for details, if it decides those details are too important not to
share, well its protecting your from yourself...


I thought I saw that EventHandlerList implemented IEnumerable, you are
correct it doesn't, so obviously you cannot use it for what you want.


Hope this helps
Jay


than
get for
user
that
I
could
get access to - that allowed me to see all the handlers/delegates
to
be
called for an event. After all, if this is not the case, how does the
framework do it?

When an event is raised, there must be a list somewhere, of delegates
that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and I have
only
called AddHandler to add a handler for an event.

Charles


message
Charles,
A specific hidden field that the designer of the class supplied when
they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty
list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection. If you
are
using the Events collection you should know what that key is. In that
you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for equality
with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to
drill
down
to the invocation list. The Item member seems to need a key in the
shape
of
an object, but what key should I use? I have searched and searched
but
cannot find an example of this anywhere. Can you think what might
work?

Thanks.

Charles


message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then

Remember that [Delegate] is short hand for System.Delegate. That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties
available
on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
events
and
but
I sender
has
see
if
my
receiver
is in it. Only if it is do I want to remove the handler. I have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object,
ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise,
get
the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Jay

Perhaps we can use as the starting point the following code, extracted from
the article that I mentioned a while back. The purpose of this code is to
map handlers in the receiver with events in the sender, based on a pattern
such as 'Event maps to OnEvent'.

<code>
Dim Method As MethodInfo

For Each ei As EventInfo In SenderType.GetEvents()
Method = ReceiverType.GetMethod(prefix & ei.Name & sufix,
bindingAttr)

If Not Method Is Nothing Then
dlgt = [Delegate].CreateDelegate(ei.EventHandlerType,
receiver, Method.Name) '***

If bind Then
ei.AddEventHandler(sender, dlgt)
Else
ei.RemoveEventHandler(sender, dlgt)
End If
End If
Next
</code>

This shows how to create a delegate using information in the EventInfo
class. Can you see how the line marked *** might be modified to create a
delegate based on the sender and not the receiver?

Charles


Jay B. Harlow said:
Charles,
You would need to get at the underlying field that is used as the backing
store for the Event. Or know the magic key to the Events property.

Remember that an Event simply encapsulates a Delegate Field, similar to how
a Property encapsulates other fields.

For example in VB.NET the Changed Event has a ChangeEvent delegate field on
the class.

Just as a Property does not need to be implemented in terms of an actual
field, an Event (in C#) does not need to be implemented in terms of a
Delegate Field. In C# the delegates can be stored in the Events property (an
EventHandlerList class). VB.NET currently does not support the Events
property.

Hope this helps
Jay


Charles Law said:
Jay

Perhaps we can approach this in another way. I have repeated my original
code below. If I don't use sender.Events - as you have explained why - is
there a way to create a delegate from ei (an EventInfo object)?

If I could create such a delegate (dlgt) , then I could use
dlgt.GetInvocationList() instead, and I would be well on my way.

What do you think?

Charles

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal receiver As
Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As System.Delegate

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()
' For each event that the sender can raise, get the invocation list
dlgts = sender.Events.Item( *WHAT GOES HERE?* ).GetInvocationList()

For Each dlgt As System.Delegate In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt
Next ei

End Sub
</code>


Encapsulation.
The it
an it
an I
have it
an as
you that
handlers/delegates
to
be
called for an event. After all, if this is not the case, how
does
the
framework do it?

When an event is raised, there must be a list somewhere, of delegates
that
will be invoked/called. If I could just get access to/enumerate those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project, and
I
have
only
called AddHandler to add a handler for an event.

Charles


message
Charles,
A specific hidden field that the designer of the class
supplied
when
they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing, or an empty
list.

Generally the class itself will create a key object (via New Object
literally) that is used to index into the Events collection.
If
you
are
using the Events collection you should know what that key is. In
that
you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for equality
with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how to
drill
down
to the invocation list. The Item member seems to need a key
in
the
shape
of
an object, but what key should I use? I have searched and searched
but
cannot find an example of this anywhere. Can you think what might
work?

Thanks.

Charles


"Jay B. Harlow [MVP - Outlook]" <[email protected]>
wrote
in
message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON
RECEIVER?*
Then
Remember that [Delegate] is short hand for
System.Delegate.
That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available
on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate
Method
properties. The System.Delegate.Equals method may or may not
help.

Hope this helps
Jay


Mr "yEaH rIgHt" posted the following link about a week
ago
in
answer
to
my
question about removing event handlers.

http://www.vbinfozine.com/t_bindevt.shtml

Following on from that post, the following issues still exist.

The article shows how to find methods on a receiver that match
the
pattern
OnXXXX given the sender. It loops through the sender events
and
tries
to
get
methods from the receiver that match the pattern. For
each
one
it
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping,
but
I
don't
have
a
straight forward mapping. For example, although I could easily
use
this
pattern in many cases, there are situations where the sender
has
two
similar
events, only one of which a particular receiver is going to
service.

Let's say that my sender has an event ValueChanged. My
receiver
could
easily
have a method OnValueChanged that could be linked up
using
the
technique
above. As it happens, my receiver has a method
MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values that can
change.
In
this
case it can raise two events: Value1Changed and Value2Changed.
My
receiver
only services one of these, and which one is determined at
runtime.
Therefore, the receiver still has a method
MyControl_ValueChanged,
because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to transform
the
event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's
events,
as
before,
but for each one I want to get the invocation list, and
see
if
my
receiver
is in it. Only if it is do I want to remove the handler. I
have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object,
ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise, get
the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON
RECEIVER?*
Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
J

Jay B. Harlow [MVP - Outlook]

Charles,
Perhaps we can use as the starting point the following code, extracted from
the article that I mentioned a while back. The purpose of this code is to
map handlers in the receiver with events in the sender, based on a pattern
such as 'Event maps to OnEvent'.
Unfortunately you are looking for a "solid" rule, where there is none. :-(

"Event maps to OnEvent" is a coding style, that I suspect most VB.NET
developers, coming from VB6, do not follow.

This shows how to create a delegate using information in the EventInfo
class. Can you see how the line marked *** might be modified to create a
delegate based on the sender and not the receiver?
Have you attempted to exchange the sender for the receiver variable and use
the same code?



Thinking about this, rather then trying to hack how Events are currently
implemented in VB.NET. Which is an implementation detail that could change.


I would expect it would be better, more correct, and safer if you
implemented your own Event Dispatcher object. Especially considering you did
mention that you are attempting to connect & disconnect these "events" at
runtime correct? (and not design time).

This Event Dispatch would track the "event", the "object" (receiver), and
the "message" (method to call). I would use a Delegate for the "object" &
"message" pair, and probably a String for the "Event" name, although any
object would work, as suggested by the Event.

The Event Dispatch object would need RaiseEvent, AddHandler, and
RemoveHandler methods, plus any others

I would either make this Event Dispatch object my base class for all the
classes in my project (a Layer Super Type pattern) or each base class would
contain an instance of the Event Dispatch object.

By implementing your own Event Dispatch object, you can add any methods you
need!

Hope this helps
Jay



Charles Law said:
Jay

Perhaps we can use as the starting point the following code, extracted from
the article that I mentioned a while back. The purpose of this code is to
map handlers in the receiver with events in the sender, based on a pattern
such as 'Event maps to OnEvent'.

<code>
Dim Method As MethodInfo

For Each ei As EventInfo In SenderType.GetEvents()
Method = ReceiverType.GetMethod(prefix & ei.Name & sufix,
bindingAttr)

If Not Method Is Nothing Then
dlgt = [Delegate].CreateDelegate(ei.EventHandlerType,
receiver, Method.Name) '***

If bind Then
ei.AddEventHandler(sender, dlgt)
Else
ei.RemoveEventHandler(sender, dlgt)
End If
End If
Next
</code>

This shows how to create a delegate using information in the EventInfo
class. Can you see how the line marked *** might be modified to create a
delegate based on the sender and not the receiver?

Charles


Jay B. Harlow said:
Charles,
You would need to get at the underlying field that is used as the backing
store for the Event. Or know the magic key to the Events property.

Remember that an Event simply encapsulates a Delegate Field, similar to how
a Property encapsulates other fields.

For example in VB.NET the Changed Event has a ChangeEvent delegate field on
the class.

Just as a Property does not need to be implemented in terms of an actual
field, an Event (in C#) does not need to be implemented in terms of a
Delegate Field. In C# the delegates can be stored in the Events property (an
EventHandlerList class). VB.NET currently does not support the Events
property.

Hope this helps
Jay
receiver
As Rather
than in
PDL
not
is
it Rather
than in
PDL
is
and
is
it is
for method -
that handlers/delegates
and
is.
In how
to
key
in
the
shape
of
an object, but what key should I use? I have searched and
searched
but
cannot find an example of this anywhere. Can you think what
might
work?

Thanks.

Charles


in
message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?*
Then

Remember that [Delegate] is short hand for System.Delegate.
That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties available
on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
mapping,
but going
to
determined
at and
see
handler.
I
have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object,
ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can
raise,
get
the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?*
Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised
text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 
C

Charles Law

Jay

I did try exchanging sender for receiver, but the Method.Name is also based
on the receiver, and does not exist on the sender.

It seems like I am wishing for the moon on a stick, and that the only way
forward is to roll my own, as you suggest. It does seem a lot of trouble to
go to though, when .NET basically has what I need built-in. I feel that I am
missing a trick somewhere.

Anyway, onwards and upwards.

Thanks again for your help.

Cheers.

Charles


Jay B. Harlow said:
Charles,
Perhaps we can use as the starting point the following code, extracted from
the article that I mentioned a while back. The purpose of this code is to
map handlers in the receiver with events in the sender, based on a pattern
such as 'Event maps to OnEvent'.
Unfortunately you are looking for a "solid" rule, where there is none. :-(

"Event maps to OnEvent" is a coding style, that I suspect most VB.NET
developers, coming from VB6, do not follow.

This shows how to create a delegate using information in the EventInfo
class. Can you see how the line marked *** might be modified to create a
delegate based on the sender and not the receiver?
Have you attempted to exchange the sender for the receiver variable and use
the same code?



Thinking about this, rather then trying to hack how Events are currently
implemented in VB.NET. Which is an implementation detail that could change.


I would expect it would be better, more correct, and safer if you
implemented your own Event Dispatcher object. Especially considering you did
mention that you are attempting to connect & disconnect these "events" at
runtime correct? (and not design time).

This Event Dispatch would track the "event", the "object" (receiver), and
the "message" (method to call). I would use a Delegate for the "object" &
"message" pair, and probably a String for the "Event" name, although any
object would work, as suggested by the Event.

The Event Dispatch object would need RaiseEvent, AddHandler, and
RemoveHandler methods, plus any others

I would either make this Event Dispatch object my base class for all the
classes in my project (a Layer Super Type pattern) or each base class would
contain an instance of the Event Dispatch object.

By implementing your own Event Dispatch object, you can add any methods you
need!

Hope this helps
Jay



Charles Law said:
Jay

Perhaps we can use as the starting point the following code, extracted from
the article that I mentioned a while back. The purpose of this code is to
map handlers in the receiver with events in the sender, based on a pattern
such as 'Event maps to OnEvent'.

<code>
Dim Method As MethodInfo

For Each ei As EventInfo In SenderType.GetEvents()
Method = ReceiverType.GetMethod(prefix & ei.Name & sufix,
bindingAttr)

If Not Method Is Nothing Then
dlgt = [Delegate].CreateDelegate(ei.EventHandlerType,
receiver, Method.Name) '***

If bind Then
ei.AddEventHandler(sender, dlgt)
Else
ei.RemoveEventHandler(sender, dlgt)
End If
End If
Next
</code>

This shows how to create a delegate using information in the EventInfo
class. Can you see how the line marked *** might be modified to create a
delegate based on the sender and not the receiver?

Charles


Charles,
You would need to get at the underlying field that is used as the backing
store for the Event. Or know the magic key to the Events property.

Remember that an Event simply encapsulates a Delegate Field, similar
to
how
a Property encapsulates other fields.

For example in VB.NET the Changed Event has a ChangeEvent delegate
field
on
the class.

Just as a Property does not need to be implemented in terms of an actual
field, an Event (in C#) does not need to be implemented in terms of a
Delegate Field. In C# the delegates can be stored in the Events
property
(an
EventHandlerList class). VB.NET currently does not support the Events
property.

Hope this helps
Jay


Jay

Perhaps we can approach this in another way. I have repeated my original
code below. If I don't use sender.Events - as you have explained
why -
is
there a way to create a delegate from ei (an EventInfo object)?

If I could create such a delegate (dlgt) , then I could use
dlgt.GetInvocationList() instead, and I would be well on my way.

What do you think?

Charles

<code>
Public Shared Sub RemoveHandlers(ByVal sender As Object, ByVal
receiver
As
Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As System.Delegate

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()
' For each event that the sender can raise, get the invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As System.Delegate In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?* Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt
Next ei

End Sub
</code>


Charles,
I didn't mean to suggest that I thought these were the same. Rather
than
get
bogged down in (perhaps) my misunderstanding, I will state my
aim
in Psychic
On" what
you not is
aim
a
C#
thing).

Incidentally, sender.Events is *not* nothing in my project,
and
I
have
only
called AddHandler to add a handler for an event.
As I stated, I would expect it to be Nothing or an empty list,
is
it
an
empty list?

Hope this helps
Jay

Jay

I did see once where New Object was used for adding keys,
but,
as
you
suggest that was in a user rolled method.

It seems, from what you are saying, that the invocation list is
for
user
use
only. I had expected that the 'framework' would have a method -
that
I
could
get access to - that allowed me to see all the handlers/delegates
to
be
called for an event. After all, if this is not the case, how does
the
framework do it?

When an event is raised, there must be a list somewhere, of
delegates
that
will be invoked/called. If I could just get access to/enumerate
those
handlers, I would be home and dry.

Incidentally, sender.Events is *not* nothing in my project,
and
I
have
only
called AddHandler to add a handler for an event.

Charles


"Jay B. Harlow [MVP - Outlook]" <[email protected]>
wrote
in
message
Charles,
A specific hidden field that the designer of the class supplied
when
they
added the Event to the HandlerList.

I suspect in your project that sender.Events is nothing,
or
an
empty
list.

Generally the class itself will create a key object (via New
Object
literally) that is used to index into the Events
collection.
If
you
are
using the Events collection you should know what that key
is.
In
that
you
would have supplied the key to add the event to the collection.

Hope this helps
Jay


Hi Jay

Yes, I think that one of those will allow me to test for
equality
with
the
receiver. My first hurdle, though is this line:

dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

Given the sender object, I cannot for the life of me see how
to
drill
down
to the invocation list. The Item member seems to need a
key
in
the
shape
of
an object, but what key should I use? I have searched and
searched
but
cannot find an example of this anywhere. Can you think what
might
work?

Thanks.

Charles


in
message
Charles,
For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?*
Then

Remember that [Delegate] is short hand for System.Delegate.
That
System.Delegate is a class with methods & properties.

I would start by looking at the methods & properties
available
on
the
System.Delegate class.
http://msdn.microsoft.com/library/d.../cpref/html/frlrfSystemDelegateClassTopic.asp
Specifically the System.Delegate.Target and System.Delegate
Method
properties. The System.Delegate.Equals method may or
may
not
help.

Hope this helps
Jay


Mr "yEaH rIgHt" posted the following link about a
week
ago
in
answer
to
my
question about removing event handlers.

http://www.vbinfozine.com/t_bindevt.shtml

Following on from that post, the following issues still
exist.

The article shows how to find methods on a receiver that
match
the
pattern
OnXXXX given the sender. It loops through the sender
events
and
tries
to
get
methods from the receiver that match the pattern.
For
each
one
it
finds
it
either adds or removes a handler for the event.

This is great where there is a straight forward mapping,
but
I
don't
have
a
straight forward mapping. For example, although I could
easily
use
this
pattern in many cases, there are situations where the
sender
has
two
similar
events, only one of which a particular receiver is going
to
service.

Let's say that my sender has an event ValueChanged. My
receiver
could
easily
have a method OnValueChanged that could be linked up using
the
technique
above. As it happens, my receiver has a method
MyControl_ValueChanged,
but
this also works with the technique above.

The problem arises where my sender has two values
that
can
change.
In
this
case it can raise two events: Value1Changed and
Value2Changed.
My
receiver
only services one of these, and which one is
determined
at
runtime.
Therefore, the receiver still has a method
MyControl_ValueChanged,
because
it knows nothing of a sender that has two values.

This breaks the pattern, as there is now easy way to
transform
the
event
Value2Changed into the method name MyControl_ValueChanged.

So, ...

I am trying to find a way of looping through the sender's
events,
as
before,
but for each one I want to get the invocation list, and
see
if
my
receiver
is in it. Only if it is do I want to remove the
handler.
I
have
got
this
far

<code>
Public Shared Sub RemoveHandlers(ByVal sender As
Object,
ByVal
receiver
As Object)

Dim SenderType As Type
Dim ReceiverType As Type

Dim dlgts() As [Delegate]

SenderType = sender.GetType()
ReceiverType = receiver.GetType()

For Each ei As EventInfo In SenderType.GetEvents()

' For each event that the sender can raise,
get
the
invocation
list
dlgts = sender.Events.Item( *WHAT GOES
HERE?* ).GetInvocationList()

For Each dlgt As [Delegate] In dlgts
If *TEST FOR DELEGATE BEING ON RECEIVER?*
Then
ei.RemoveEventHandler(sender, dlgt)
End If
Next dlgt

Next ei

End Sub
</code>

Can someone suggest what might replace the capitalised
text?
Alternatively,
can
anyone think of another way of achieving the same end?

Thanks.

Charles
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top