EventHandlerList question (1.1)

  • Thread starter Thread starter DeveloperX
  • Start date Start date
D

DeveloperX

I'm having a play with EventHandlerList but the documentation is a bit
ropey and I can't find any decent examples. It also doesn't seem to do
what I was led to believe it would. I was under the impression that
windows.forms controls used EventHandlerLists because generally most
events aren't consumed so this saves memory.
I can add a button to a form, and have

this.button9.Click += new System.EventHandler(this.button9_Click);
this.button9.Click += new System.EventHandler(this.button9b_Click);

which will successfully fire off both functions when the button is
clicked.

The EventHandlerList does not fire both as it keys the delegate in a
hashtable and overwrites the first reference with the second reference
(This is using AddHandler).
More confusingly in trying to get the thing running I see code all over
the internet that can't run. A VB example that used a foreach (there's
no enumerator so that can't work) and a C++ example where the
EventHandlerList returns an EventHandler (It only returns Delegates in
my tests)
I'm certain I'm right, I can see plenty of alternative ways of doing it
that would work, I'm just confused about the information I'm getting
off the internet.
So am I being fed porkies? Do Windows Forms controls use
EventHandlerList objects and if so how come their implementation allows
for += and the one in ComponentModel doesn't?

Thanks
Ian
 
Hi Ian,

I was under the impression that
windows.forms controls used EventHandlerLists because generally most
events aren't consumed so this saves memory.
True.

I can add a button to a form, and have

this.button9.Click += new System.EventHandler(this.button9_Click);
this.button9.Click += new System.EventHandler(this.button9b_Click);

which will successfully fire off both functions when the button is
clicked.

The EventHandlerList does not fire both as it keys the delegate in a
hashtable and overwrites the first reference with the second reference
(This is using AddHandler).

Here's an example that I'm using from a project I'm working on right now in a
class that derives from Component:

private readonly object ServiceViewChangedEvent = new object();

public event EventHandler<ServiceViewChangedEventArgs> ServiceViewChanged
{
add
{
lock (ServiceViewChangedEvent)
{
Events.AddHandler(ServiceViewChangedEvent, value);
}
}
remove
{
lock (ServiceViewChangedEvent)
{
Events.RemoveHandler(ServiceViewChangedEvent, value);
}
}
}

private void OnServiceViewChanged(ServiceViewChangedEventArgs e)
{
EventHandler<ServiceViewChangedEventArgs> handler = null;

lock (ServiceViewChangedEvent)
{
handler = (EventHandler<ServiceViewChangedEventArgs>)
Events[ServiceViewChangedEvent];
}

if (handler != null)
handler(this, e);
}
More confusingly in trying to get the thing running I see code all over
the internet that can't run. A VB example that used a foreach (there's
no enumerator so that can't work) and a C++ example where the
EventHandlerList returns an EventHandler (It only returns Delegates in
my tests)

EventHandler is a delegate. The value returned by the EventHandlerList
indexer isn't type-safe, so it must be cast into the appropriate delegate
Type, as you can see in the code above.
I'm certain I'm right, I can see plenty of alternative ways of doing it
that would work, I'm just confused about the information I'm getting
off the internet.
So am I being fed porkies? Do Windows Forms controls use
EventHandlerList objects and if so how come their implementation allows
for += and the one in ComponentModel doesn't?

An EventHandlerList instance is exposed as a protected property named,
"Events" from the Component class to all derived types. The "+=" operator
acts on public events, not the "Events" property. The underlying
implementation of "add" and "remove" on these public events can use the
"Events" property, internally, to store the supplied delegate.

Yes, I'm sure WinForms controls use the Events property, though I'm not sure
if ALL events on ALL WinForms Controls are registered through the inherited
Component.Events property. Web controls use the "Events" property as well,
but it's declared in the base Control since Control doesn't derive from
Component. It still works the same way.

In my example, the public event is "ServiceViewChanged". The "add" and
"remove" implementations of that event, which correspond to the "+=" and "-="
operators, respectively, add or remove the supplied delegate to or from the
underlying EventHandlerList by calling either Events.AddHandler or
Events.RemoveHandler. Both of these methods require the same key used in the
indexer when you attempt to retrieve the delegate reference from the list.

If things still aren't clear, let me know.
 
Hi Ian,

Sorry about using C# generics - I just realized you wrote (1.1) in the title.

To be honest, I don't have a code snippet without generics on hand anyway. If
you need me to rewrite my example without generics I will - just let me know.

--
Dave Sexton

Dave Sexton said:
Hi Ian,

I was under the impression that
windows.forms controls used EventHandlerLists because generally most
events aren't consumed so this saves memory.
True.

I can add a button to a form, and have

this.button9.Click += new System.EventHandler(this.button9_Click);
this.button9.Click += new System.EventHandler(this.button9b_Click);

which will successfully fire off both functions when the button is
clicked.

The EventHandlerList does not fire both as it keys the delegate in a
hashtable and overwrites the first reference with the second reference
(This is using AddHandler).

Here's an example that I'm using from a project I'm working on right now in
a class that derives from Component:

private readonly object ServiceViewChangedEvent = new object();

public event EventHandler<ServiceViewChangedEventArgs> ServiceViewChanged
{
add
{
lock (ServiceViewChangedEvent)
{
Events.AddHandler(ServiceViewChangedEvent, value);
}
}
remove
{
lock (ServiceViewChangedEvent)
{
Events.RemoveHandler(ServiceViewChangedEvent, value);
}
}
}

private void OnServiceViewChanged(ServiceViewChangedEventArgs e)
{
EventHandler<ServiceViewChangedEventArgs> handler = null;

lock (ServiceViewChangedEvent)
{
handler = (EventHandler<ServiceViewChangedEventArgs>)
Events[ServiceViewChangedEvent];
}

if (handler != null)
handler(this, e);
}
More confusingly in trying to get the thing running I see code all over
the internet that can't run. A VB example that used a foreach (there's
no enumerator so that can't work) and a C++ example where the
EventHandlerList returns an EventHandler (It only returns Delegates in
my tests)

EventHandler is a delegate. The value returned by the EventHandlerList
indexer isn't type-safe, so it must be cast into the appropriate delegate
Type, as you can see in the code above.
I'm certain I'm right, I can see plenty of alternative ways of doing it
that would work, I'm just confused about the information I'm getting
off the internet.
So am I being fed porkies? Do Windows Forms controls use
EventHandlerList objects and if so how come their implementation allows
for += and the one in ComponentModel doesn't?

An EventHandlerList instance is exposed as a protected property named,
"Events" from the Component class to all derived types. The "+=" operator
acts on public events, not the "Events" property. The underlying
implementation of "add" and "remove" on these public events can use the
"Events" property, internally, to store the supplied delegate.

Yes, I'm sure WinForms controls use the Events property, though I'm not sure
if ALL events on ALL WinForms Controls are registered through the inherited
Component.Events property. Web controls use the "Events" property as well,
but it's declared in the base Control since Control doesn't derive from
Component. It still works the same way.

In my example, the public event is "ServiceViewChanged". The "add" and
"remove" implementations of that event, which correspond to the "+=" and
"-=" operators, respectively, add or remove the supplied delegate to or from
the underlying EventHandlerList by calling either Events.AddHandler or
Events.RemoveHandler. Both of these methods require the same key used in
the indexer when you attempt to retrieve the delegate reference from the
list.

If things still aren't clear, let me know.
 
Thanks Dave, no problem on the Generics, I use 2 at home, 1.1 at work.
There are some changes in 2 that affect Events in VB.net, so I
specified 1.1 in case those changes were part of some underlying change
in 2. I could of made that much much clearer :)

Give me a while to digest the info and I'll let you know if I have any
joy
Cheers

Dave said:
Hi Ian,

Sorry about using C# generics - I just realized you wrote (1.1) in the title.

To be honest, I don't have a code snippet without generics on hand anyway. If
you need me to rewrite my example without generics I will - just let me know.

--
Dave Sexton

Dave Sexton said:
Hi Ian,

I was under the impression that
windows.forms controls used EventHandlerLists because generally most
events aren't consumed so this saves memory.
True.

I can add a button to a form, and have

this.button9.Click += new System.EventHandler(this.button9_Click);
this.button9.Click += new System.EventHandler(this.button9b_Click);

which will successfully fire off both functions when the button is
clicked.

The EventHandlerList does not fire both as it keys the delegate in a
hashtable and overwrites the first reference with the second reference
(This is using AddHandler).

Here's an example that I'm using from a project I'm working on right now in
a class that derives from Component:

private readonly object ServiceViewChangedEvent = new object();

public event EventHandler<ServiceViewChangedEventArgs> ServiceViewChanged
{
add
{
lock (ServiceViewChangedEvent)
{
Events.AddHandler(ServiceViewChangedEvent, value);
}
}
remove
{
lock (ServiceViewChangedEvent)
{
Events.RemoveHandler(ServiceViewChangedEvent, value);
}
}
}

private void OnServiceViewChanged(ServiceViewChangedEventArgs e)
{
EventHandler<ServiceViewChangedEventArgs> handler = null;

lock (ServiceViewChangedEvent)
{
handler = (EventHandler<ServiceViewChangedEventArgs>)
Events[ServiceViewChangedEvent];
}

if (handler != null)
handler(this, e);
}
More confusingly in trying to get the thing running I see code all over
the internet that can't run. A VB example that used a foreach (there's
no enumerator so that can't work) and a C++ example where the
EventHandlerList returns an EventHandler (It only returns Delegates in
my tests)

EventHandler is a delegate. The value returned by the EventHandlerList
indexer isn't type-safe, so it must be cast into the appropriate delegate
Type, as you can see in the code above.
I'm certain I'm right, I can see plenty of alternative ways of doing it
that would work, I'm just confused about the information I'm getting
off the internet.
So am I being fed porkies? Do Windows Forms controls use
EventHandlerList objects and if so how come their implementation allows
for += and the one in ComponentModel doesn't?

An EventHandlerList instance is exposed as a protected property named,
"Events" from the Component class to all derived types. The "+=" operator
acts on public events, not the "Events" property. The underlying
implementation of "add" and "remove" on these public events can use the
"Events" property, internally, to store the supplied delegate.

Yes, I'm sure WinForms controls use the Events property, though I'm not sure
if ALL events on ALL WinForms Controls are registered through the inherited
Component.Events property. Web controls use the "Events" property as well,
but it's declared in the base Control since Control doesn't derive from
Component. It still works the same way.

In my example, the public event is "ServiceViewChanged". The "add" and
"remove" implementations of that event, which correspond to the "+=" and
"-=" operators, respectively, add or remove the supplied delegate to or from
the underlying EventHandlerList by calling either Events.AddHandler or
Events.RemoveHandler. Both of these methods require the same key used in
the indexer when you attempt to retrieve the delegate reference from the
list.

If things still aren't clear, let me know.
 
Dave said:
Hi Ian,

Sorry about using C# generics - I just realized you wrote (1.1) in the title.

To be honest, I don't have a code snippet without generics on hand anyway. If
you need me to rewrite my example without generics I will - just let me know.

--
Dave Sexton

Dave Sexton said:
Hi Ian,

I was under the impression that
windows.forms controls used EventHandlerLists because generally most
events aren't consumed so this saves memory.
True.

I can add a button to a form, and have

this.button9.Click += new System.EventHandler(this.button9_Click);
this.button9.Click += new System.EventHandler(this.button9b_Click);

which will successfully fire off both functions when the button is
clicked.

The EventHandlerList does not fire both as it keys the delegate in a
hashtable and overwrites the first reference with the second reference
(This is using AddHandler).

Here's an example that I'm using from a project I'm working on right now in
a class that derives from Component:

private readonly object ServiceViewChangedEvent = new object();

public event EventHandler<ServiceViewChangedEventArgs> ServiceViewChanged
{
add
{
lock (ServiceViewChangedEvent)
{
Events.AddHandler(ServiceViewChangedEvent, value);
}
}
remove
{
lock (ServiceViewChangedEvent)
{
Events.RemoveHandler(ServiceViewChangedEvent, value);
}
}
}

private void OnServiceViewChanged(ServiceViewChangedEventArgs e)
{
EventHandler<ServiceViewChangedEventArgs> handler = null;

lock (ServiceViewChangedEvent)
{
handler = (EventHandler<ServiceViewChangedEventArgs>)
Events[ServiceViewChangedEvent];
}

if (handler != null)
handler(this, e);
}
More confusingly in trying to get the thing running I see code all over
the internet that can't run. A VB example that used a foreach (there's
no enumerator so that can't work) and a C++ example where the
EventHandlerList returns an EventHandler (It only returns Delegates in
my tests)

EventHandler is a delegate. The value returned by the EventHandlerList
indexer isn't type-safe, so it must be cast into the appropriate delegate
Type, as you can see in the code above.
I'm certain I'm right, I can see plenty of alternative ways of doing it
that would work, I'm just confused about the information I'm getting
off the internet.
So am I being fed porkies? Do Windows Forms controls use
EventHandlerList objects and if so how come their implementation allows
for += and the one in ComponentModel doesn't?

An EventHandlerList instance is exposed as a protected property named,
"Events" from the Component class to all derived types. The "+=" operator
acts on public events, not the "Events" property. The underlying
implementation of "add" and "remove" on these public events can use the
"Events" property, internally, to store the supplied delegate.

Yes, I'm sure WinForms controls use the Events property, though I'm not sure
if ALL events on ALL WinForms Controls are registered through the inherited
Component.Events property. Web controls use the "Events" property as well,
but it's declared in the base Control since Control doesn't derive from
Component. It still works the same way.

In my example, the public event is "ServiceViewChanged". The "add" and
"remove" implementations of that event, which correspond to the "+=" and
"-=" operators, respectively, add or remove the supplied delegate to or from
the underlying EventHandlerList by calling either Events.AddHandler or
Events.RemoveHandler. Both of these methods require the same key used in
the indexer when you attempt to retrieve the delegate reference from the
list.

If things still aren't clear, let me know.

You were spot on with the assertion that I needed to cast the Delegate
to the correct type. I had previously attempted to cast it to an
EventHandler with didn't work. The reason being I was using an example
borrowed from MS which uses MouseEventHandler (Their code only went as
far as adding the delegate to the list not firing it).

I now have it working both by deriving from Component and using Events,
and with a EventHandlerList declared in the class.

Thanks for your help
Ian
 

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

Back
Top