PC Review


Reply
Thread Tools Rate Thread

Button.Click as EventHandler via reflection [why not possible?]

 
 
Wiktor Zychla
Guest
Posts: n/a
 
      15th Feb 2005
Let's start with an example: if you have:

class Test
{
public delegate int MyDelegate( int n );
event MyDelegate MyEvent;
}

then you can get MyEvent using reflection:

Test test = new Test(...);
Type t = typeof( Test );
t.InvokeMember( "MyEvent", BindingFlags.Instance | BindingFlags.GetField |
BindingFlags.NonPublic, null, test, null );

this works like a charm, you get reference to the delegate of type
MyDelegate.

Then comes the problem: why following does not work:

class MyForm : Form
{
Button b;
...
}

Type t = typeof( Button );
t.InvokeMember( "Click", BindingFlags.Instance | BindingFlags.GetField |
BindingFlags.NonPublic, null, b, null );

this example looks like a perfect copy of above one. Click event is declared
as field in Control class and thus, according to my intuition, should be
available via reflection. I would expect to get a delegate of type
EventHandler. instead an exception of missing member is thrown.

I just hope I miss something obvious. If not, I really would like to hear a
technical explanation, can be complicated, I am not afraid [I know how
delegates and events work at IL level].

Thanks in advance,
Wiktor Zychla


 
Reply With Quote
 
 
 
 
Magnus Krisell
Guest
Posts: n/a
 
      15th Feb 2005
Hi Wiktor,

Interesting example.
The behaviour you're observing must be due to the fact that the
Click event of the Button class isn't implemented as a delegate field.
Though events are usually implemented that way (as in your first
example) alternative ways are possible.

Paragraph 17.7.2 of the C# languague specification (the ECMA version)
talks about manually implementing event accessors:

"One situation for doing so involves the case in which the storage cost
of one field per event is not acceptable. In such cases, a class can include
event-accessor-declarations and use a private mechanism for storing the
list of event handlers."

- Magnus

"Wiktor Zychla" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Let's start with an example: if you have:
>
> class Test
> {
> public delegate int MyDelegate( int n );
> event MyDelegate MyEvent;
> }
>
> then you can get MyEvent using reflection:
>
> Test test = new Test(...);
> Type t = typeof( Test );
> t.InvokeMember( "MyEvent", BindingFlags.Instance | BindingFlags.GetField |
> BindingFlags.NonPublic, null, test, null );
>
> this works like a charm, you get reference to the delegate of type
> MyDelegate.
>
> Then comes the problem: why following does not work:
>
> class MyForm : Form
> {
> Button b;
> ...
> }
>
> Type t = typeof( Button );
> t.InvokeMember( "Click", BindingFlags.Instance | BindingFlags.GetField |
> BindingFlags.NonPublic, null, b, null );
>
> this example looks like a perfect copy of above one. Click event is
> declared as field in Control class and thus, according to my intuition,
> should be available via reflection. I would expect to get a delegate of
> type EventHandler. instead an exception of missing member is thrown.
>
> I just hope I miss something obvious. If not, I really would like to hear
> a technical explanation, can be complicated, I am not afraid [I know how
> delegates and events work at IL level].
>
> Thanks in advance,
> Wiktor Zychla
>



 
Reply With Quote
 
Wiktor Zychla
Guest
Posts: n/a
 
      15th Feb 2005
> Interesting example.
> The behaviour you're observing must be due to the fact that the
> Click event of the Button class isn't implemented as a delegate field.
> Though events are usually implemented that way (as in your first
> example) alternative ways are possible.
>
> Paragraph 17.7.2 of the C# languague specification (the ECMA version)
> talks about manually implementing event accessors:
>
> "One situation for doing so involves the case in which the storage cost
> of one field per event is not acceptable. In such cases, a class can
> include
> event-accessor-declarations and use a private mechanism for storing the
> list of event handlers."



brilliant!!! I've decompiled System.Windows.Forms to find out that this is
true: the Click event is handled via two methods: add_Click and
remove_Click. I've decompiled these methods. this is the result of applying
this knowledge to the Button example:


Type t = typeof(System.ComponentModel.Component);
System.ComponentModel.EventHandlerList eh =
(System.ComponentModel.EventHandlerList)t.InvokeMember( "Events",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, b, null );



now I can see all handlers assigned to the event: the EventHandlerList has
private property 'head' that points to the first handler and each handler
has 'next' property that points to next handler.



thanks for the idea Magnus!



Wiktor Zychla


 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Dinamically Add or Remove an EventHandler from a DataGridView Control using Reflection Etienne-Louis Nicolet Microsoft VB .NET 0 31st Jan 2009 12:28 PM
Newbie question - Runtime Button and EventHandler Mr Not So Know It All Microsoft ASP .NET 9 28th Mar 2007 01:51 AM
How to fire both event button click and textchanged when button is click and text is changed Amy Microsoft ASP .NET 0 1st Jun 2006 03:33 PM
help:I want remove all eventhandler of Click, how can I realize it yy Microsoft Dot NET Compact Framework 1 22nd Feb 2005 01:45 PM
Adding Eventhandler for a Button in datagrid... in runtime? Lars Netzel Microsoft ASP .NET 0 9th Jul 2004 11:09 AM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 06:32 PM.