Click here to Skip to main content
13,555,796 members
Click here to Skip to main content
Add your own
alternative version

Tagged as


24 bookmarked
Posted 4 Apr 2009
Licenced CPOL

Get Delegate from Event's Subscription

, 4 Apr 2009
Rate this:
Please Sign up or sign in to vote.
This code allows you to get a delegate that subscribed to a Control's event. The technique used is applicable to events in general.


This code allows you to get a delegate that subscribed to a Control's event. The technique used is applicable to events in general.


Recently I came across a problem. The task was to extend the functionality of some third-party control. No source code is available, all public classes are sealed. I needed to change the behavior of a button that showed SaveFileDialog and then rendered a report with default settings. There was no way to change the settings of render but to rewrite all control's toolbar.

But all I needed was to change the handler of a Click event on a control's button. To do that, one should unsubscribe old handler (-=) and subscribe a new one (+=). The question is - how to get the old handler when you don't have access to it?

To think about it, the same situation arises when a developer wants to unsubscribe from an anonymous delegate or lambda expression. There is no name to reference them (apart from storing it beforehand in a variable. But anonymous delegates, you know... should stay anonymous).


First let's see the event storing background. I was to modify the behavior of a ToolStripButton so we'll dig from it.

Reflector shows that there are only two events in the ToolStripButton class. But there are a bunch of them in the base ToolStripItem class. The Click event for example is defined like:

public event EventHandler Click
    add { base.Events.AddHandler(EventClick, value); }
    remove { base.Events.RemoveHandler(EventClick, value); }

We see that there is an Events collection that stores all subscribed delegates. And the kind of event is determined by the key object - EventClick in this case:

public abstract class ToolStripItem: Component, ...
    internal static readonly object EventClick;

The Events collection (of type EventHandlerList) is stored in System.ComponentModel.Component class and has an interesting method Find:

public sealed class EventHandlerList : ...
    private ListEntry Find(object key);
    private sealed class ListEntry
        internal Delegate handler;


In summary, to get access to a delegate that subscribed to the Click event, one could write something like:

control.Events.Find( control.EventClick ).handler 

But encapsulation won't allow it. Luckily there is a way to achieve that - reflection. The code will be:

var handler = (EventHandler) GetDelegate( toolStripButton, "EventClick" );
private static object GetDelegate( Component issuer, string keyName )
    // Get key value for a Click Event
    var key = issuer
        .GetType( )
        .GetField( keyName, BindingFlags.Static | 
		BindingFlags.NonPublic | BindingFlags.FlattenHierarchy )
        .GetValue( null );
    // Get events value to get access to subscribed delegates list
    var events = typeof( Component )
        .GetField( "events", BindingFlags.Instance | BindingFlags.NonPublic )
        .GetValue( issuer );
    // Find the Find method and use it to search up listEntry for corresponding key
    var listEntry = typeof( EventHandlerList )
        .GetMethod( "Find", BindingFlags.NonPublic | BindingFlags.Instance )
        .Invoke( events, new object[] { key } );
    // Get handler value from listEntry 
    var handler = listEntry
        .GetType( )
        .GetField( "handler", BindingFlags.Instance | BindingFlags.NonPublic )
        .GetValue( listEntry );
    return handler;

Available event keys (it's not only "EventClick" you know...) can be accessed with a method:

private static IEnumerable<string> GetEventKeysList( Component issuer )
        from key in issuer.GetType( ).GetFields( BindingFlags.Static | 
		BindingFlags.NonPublic | BindingFlags.FlattenHierarchy )
        where key.Name.StartsWith( "Event" )
        select key.Name;

The code with the article contains a project that demonstrates all techniques described.


The event manipulation syntax in C# was made restrictive with a purpose. It will not break event encapsulation. It is by design and it is the right thing.

A situation when you need to access an unknown delegate that subscribed to a known event is rare. But it exists. I hope this article saved you some time when you came across such a problem.


  • 5th April, 2009: Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Alexander Kostikov
Russian Federation Russian Federation
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralThe best event copy code! Pin
omzig6-Dec-10 14:06
memberomzig6-Dec-10 14:06 
GeneralDoesn't work with a Button Pin
Member 25735233-Dec-09 8:35
memberMember 25735233-Dec-09 8:35 
GeneralA small problem: a lot of the keys are in private fields in base classes Pin
jnky_boy16-Sep-09 8:28
memberjnky_boy16-Sep-09 8:28 
GeneralRe: A small problem: a lot of the keys are in private fields in base classes Pin
Alexander Kostikov16-Sep-09 9:10
memberAlexander Kostikov16-Sep-09 9:10 
GeneralThank you for sharing... Pin
Oleg Shilo21-Jun-09 0:14
memberOleg Shilo21-Jun-09 0:14 
GeneralThanks Pin
gpgemini5-Apr-09 9:28
membergpgemini5-Apr-09 9:28 
GeneralRe: Thanks Pin
Alexander Kostikov6-Apr-09 1:34
memberAlexander Kostikov6-Apr-09 1:34 
QuestionPotential uses? Pin
Dmitri Nesteruk4-Apr-09 23:55
memberDmitri Nesteruk4-Apr-09 23:55 
AnswerRe: Potential uses? Pin
Alexander Kostikov5-Apr-09 7:13
memberAlexander Kostikov5-Apr-09 7:13 
AnswerRe: Potential uses? Pin
OrlandoCurioso5-Apr-09 9:28
memberOrlandoCurioso5-Apr-09 9:28 
I have used this to clone ToolStripItem's. To copy the subscribers of the events,
I had to use Reflection to access the private EventHandlerList.


Try again. Fail again. Fail better. --- Samuel Beckett

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04-2016 | 2.8.180515.1 | Last Updated 5 Apr 2009
Article Copyright 2009 by Alexander Kostikov
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid