Sunday, 9 January 2011

Secret Project

Well I said I would reveal the secret project I've been working on. 99% of people won't be interested, but if you're a .NET developer you probably will be very interested. Especially if you do a lot of UI work.

I actually came up with this idea 6 years ago and wrote a fairly successful codeproject article on it, but then I abandoned it. I've since started a new job, and wished I had this tool, so built it.

Enter Event Spy -


Event spy is a development/debugging tool that subscribes to all events a .NET object can raise, it then records when events are raised on the object, and allows you to explore the value of any event arguments.

Event spy works on any event of any object, no matter what the event handler type is. It does this by using a combination of runtime code generation through CodeDOM and Reflection.Emit to compile handlers on the fly.

Usage is pretty simple, just add Event Spy as a reference, then call:

var spy = new EventSpy();
spy.Register(o);

where o is any object. Event spy will then start listening to all events the object exposes, and will pop up a window that shows these events in real time. You can even register more than 1 object at once with event spy.

The reasoning behind event spy is that when you're faced with using a new control or API library it's a massive pain to trawl through documentation to work out what events are available, when they are raised and what gets passed to the handler. With this you can simply register the control or object, and play about with it to work all this out.

Event spy works well with multithreaded applications - the main window runs in its own dedicated STA thread (which is handy, as it means you can call from an MTA thread if you wish). The event handlers that event spy generates at runtime run on whatever thread called spy.Register. One issue is that in the parameter explorer at the bottom you may navigate through to some UIElement that isn't on event spys UI thread. I've handled this situation by ensuring that whenever a UIElement is encountered event spy will do the work it needs to on that UIElements associated dispatcher.

A build and the source (VS 2010 project) are below, please give it a whirl and give any feedback.

Roadmap wise the next big feature will be deep cloning of handler parameters using Reflection.Emit.Say you have subscribed to TextChanged of a System.Windows.Control.TextBox, and change type 'hi' in the text box. 2 events will be raised for this - one when you type h, another when you type i. At the minute event spy doesn't do any deep copying of handler arguments, so the sender argument of both events will each point to the TextBox object as it currently stands (with text 'hi') as opposed to a freezed snapshot of the textbox state at the point in time the event occured. This feature will reduce performance a lot, but will be a handy thing to have. That should hopefully be done in the next few weeks. Deep cloning of arbitrary objects (i.e. that may not implement IClonable) should be a pretty interesting problem, so I will post about that when I get around to it.

Build - http://www.box.net/shared/3eds1cpg96
Source - http://www.box.net/shared/o8vlo1zhqs

14 comments:

  1. Awesome, I am currently developing an event recorder for any kind of Windows event using hooks. This will help me get mor detail on the .net applications!

    ReplyDelete
  2. Next step is to take routed events, show the element which they started on and the element which handled it.

    ReplyDelete
  3. I wish something like this existed for PyGTK.

    ReplyDelete
  4. Thank you very much for this awesome tool. In retrospect this should be a default tool in .Net.

    ReplyDelete
  5. will this work with asp.net projects

    ReplyDelete
  6. Also may be used to find possible memory leaks. I've had events cause havoc in the past. Am I right martin?

    ReplyDelete
  7. Another ASP.NET user here, any goodies for us?

    ReplyDelete
  8. I tried it with ASP.NET and tried displaying the Page events. It worked fine on the first run, but when I reload the page, the ASP.NET Development server crashes mercilessly. But maybe it's just me. ;)

    ReplyDelete
  9. Will have a play about and see if I can get it working consistently

    ReplyDelete
  10. Martin, I'm trying to use your code in a WinForm application. Any tricks to get it to work properly?

    ReplyDelete
  11. nice post and useful because it's open source :)

    ReplyDelete
  12. really great! it seems like this should be a standard feature in VS

    ReplyDelete
  13. Any chance you'd be willing to post it on codeplex? Pretty please? :)

    ReplyDelete
  14. Hey James,

    It's on codeplex, look at my latest post. Can't say that I've had time to work on it since however. Please contribute if you can!

    ReplyDelete