views:

286

answers:

3

Is there a way to list all fired events for specific WinForms controls without explicitly creating a handler for each possible event? For example, I might want to see the sequence of events that fire between a DataGridView and the BindingSource during various databinding actions.

+1  A: 

I think you could use Reflection to do this.

John Saunders
A: 

This cannot be done. If you use Reflector to view a lot of the Framework's classes you'll find a common pattern when firing events:

// fire event
if (EventDelegate != null)
   EventDelegate(eventArgs);

So the event is not even fired if no one is subscribing to it

mjmarsh
I don't see why that means it can't be done - it just means that the event needs to be subscribed to. There's a big difference between that and *explicitly* subscribing to each event in code.
Jon Skeet
I think you're splitting hairs. Either by creating hard coded delegates or using reflection you're still 'explicitly' adding event handlers. My response assumed he didn't want to subscribe to the events at all (even via reflection) but wanted to see the sequence of events in some other fashion.
mjmarsh
+1  A: 

You could use reflection, but it's going to be slightly tricky because of the various event handler signatures involved. Basically you'd have to get the EventInfo for each event in the type, and use the EventHandlerType property to work out what delegate type to create before calling AddEventHandler. Delegate.CreateDelegate works for everything that follows the normal event handler pattern though...

Gere's a sample app. Note that it's not doing any checking - if you give it something with a "non-standard" event it will throw an exception. You could fairly easily use reflection to print out the event args too.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;

namespace ConsoleApp
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Form form = new Form { Size = new Size(400, 200) };
            Button button = new Button { Text = "Click me" };
            form.Controls.Add(button);
            EventSubscriber.SubscribeAll(button);
            Application.Run(form);
        }
    }

    class EventSubscriber
    {
        private static readonly MethodInfo HandleMethod = 
            typeof(EventSubscriber)
                .GetMethod("HandleEvent", 
                           BindingFlags.Instance | 
                           BindingFlags.NonPublic);

        private readonly EventInfo evt;

        private EventSubscriber(EventInfo evt)
        {
            this.evt = evt;
        }

        private void HandleEvent(object sender, EventArgs args)
        {
            Console.WriteLine("Event {0} fired", evt.Name);
        }

        private void Subscribe(object target)
        {
            Delegate handler = Delegate.CreateDelegate(
                evt.EventHandlerType, this, HandleMethod);
            evt.AddEventHandler(target, handler);
        }

        public static void SubscribeAll(object target)
        {
            foreach (EventInfo evt in target.GetType().GetEvents())
            {
                EventSubscriber subscriber = new EventSubscriber(evt);
                subscriber.Subscribe(target);
            }
        }
    }
}
Jon Skeet
Exactly what I was looking for! Looks like I need to do some serious reading and tinkering with reflection. Thanks!
BikeMrown