Click here to Skip to main content
15,895,809 members
Articles / Programming Languages / C#

Get Delegate from Event's Subscription

Rate me:
Please Sign up or sign in to vote.
4.00/5 (8 votes)
4 Apr 2009CPOL2 min read 40.2K   367   25  
This code allows you to get a delegate that subscribed to a Control's event. The technique used is applicable to events in general.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace DelegateFromSubscription
{
    public class Program
    {
        public static void Main( string[] args )
        {
            // Event publisher
            var toolStripButton = new ToolStripButton( );

            // We want to unsubsribe from this delegate
            toolStripButton.Click += delegate { MessageBox.Show( "I was found!" ); };

            // Search for the delegate and make sure that it's it
            var handler = (EventHandler) GetDelegate( toolStripButton, "EventClick" );
            handler.Invoke( null, null );

            // Unsubscribe from the delegate
            toolStripButton.Click -= handler;

            // What other event keys can we use
            PrintEventKeys( toolStripButton );
            Console.ReadLine( );
        }

        /// <summary>
        /// Prints all event keys of a control
        /// </summary>
        private static void PrintEventKeys( Component issuer )
        {
            Console.WriteLine( "Allowed event keys:" );
            foreach( var key in GetEventKeysList( issuer ) )
            {
                Console.WriteLine( "- " + key );
            }
        }

        /// <summary>
        /// Gets list of all event keys for a control
        /// </summary>
        private static IEnumerable<string> GetEventKeysList( Component issuer )
        {
            return
                from key in issuer.GetType( ).GetFields( BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy )
                where key.Name.StartsWith( "Event" )
                select key.Name;
        }

        /// <summary>
        /// Get delegate that listens an event of a component
        /// </summary>
        /// <param name="issuer">Component with an event</param>
        /// <param name="keyName">Key of event(<seealso cref="GetEventKeysList"/>)</param>
        /// <example>
        /// toolStripButton.Click += delegate { MessageBox.Show( "I was found!" ); };
        /// toolStripButton.Click -= (EventHandler) GetDelegate( toolStripButton, "EventClick" );
        /// </example>
        private static object GetDelegate( Component issuer, string keyName )
        {
            // Get key value for a Click Event
            // (key = internal static readonly object ToolStripItem.EventClick)
            var key = issuer
                .GetType( )
                .GetField( keyName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy )
                .GetValue( null );

            // Get events value to get access to subscribed delegates list
            // (events = protected EventHandlerList Component.events)
            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
            // (listEntry = Events.Find( key ))
            var listEntry = typeof( EventHandlerList )
                .GetMethod( "Find", BindingFlags.NonPublic | BindingFlags.Instance )
                .Invoke( events, new object[] { key } );

            // Get handler value from listEntry 
            // (handler = listEntry.handler )
            var handler = listEntry
                .GetType( )
                .GetField( "handler", BindingFlags.Instance | BindingFlags.NonPublic )
                .GetValue( listEntry );

            return handler;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions