Track (all) the events from a Control
Simple situation(VS2005, .NET2): I have a textBox1 on a panel1. I need to track all the emitted events from this textBox1.
Actually, when I need to track a single event(TextChanged, by e.g.) from this textBox1 I add a handler to the (TextChanged event) I set then a non-blocking breackpoint that writes on the output console a message containing the function (eventhandler) name. So, for a single event I can write this handler and set the breackpoint, but can I do something similar for all possible textbox(or other control)'s events?
alt text http://lh5.ggpht.com/_1TPOP7DzY1E/S0H5NHjXSjI/AAAAAAAA开发者_开发问答C24/tV0IiUsxwAU/s800/eventsTrack.png
More deeply, I need to know what event have place in a certain moment on the mentioned control (textBox).
Thanks.
Aviad's post is a good start. You can use it for events of type EventHandler
. For other delegate types you can use the same technique creating handler for each type manually.
If you want to be more flexible you should create event handler in runtime using System.Reflection.Emit
. Here is a detailed explanation: http://msdn.microsoft.com/en-us/library/ms228976.aspx. Scroll down to "To generate an event handler at run time by using a dynamic method" title.
//EDIT
I created simple class which is able to handle all events of particular object and pass them to universal event handler. Code is based on examples from Microsoft and XTreme.NET Talk.
Basic idea
- create method in runtime which has the same arguments as event
- set this mehod as event handler for each event in Type.GetEvents()
- from this method call universal event handler
Usage
Object to attach to is passed in constructor. Next anonymous method of type UniversalEventHandler
is used to handle all events. This method receives event name as eventName
and event arguments in args
. You can set breakpoint on this method and inspect arguments in Visual Studio or print them by yourself. In this sample usage only event name is printed and can be found in Output window (menu View > Output in Visual Studio). In this example standard button button1
is examined.
private void Form1_Load(object sender, EventArgs e)
{
UniversalEventHandler handler = (UniversalEventHandler) delegate(string eventName, object[] args)
{
System.Diagnostics.Trace.WriteLine(eventName);
};
EventInspector inspector = new EventInspector(button1, handler);
}
Code
public delegate void UniversalEventHandler(string eventName, object[] args);
public class EventInspector
{
private UniversalEventHandler eventHandler;
private object srcObject;
public EventInspector(object srcObject, UniversalEventHandler eventHandler)
{
this.eventHandler = eventHandler;
this.srcObject = srcObject;
Attach();
}
public void EventReceived(string eventName, object[] args)
{
if (eventHandler != null)
eventHandler(eventName, args);
}
public void Attach()
{
Type type = srcObject.GetType();
EventInfo[] srcEvents = type.GetEvents();
for (int i = 0; i < srcEvents.Length; i++)
{
EventInfo srcEvent = srcEvents[i];
Type[] parameterTypes = GetDelegateParams(srcEvent.EventHandlerType);
DynamicMethod handler = new DynamicMethod("", typeof(void), parameterTypes, typeof(EventInspector));
string name = srcEvent.Name;
ILGenerator il = handler.GetILGenerator();
il.DeclareLocal(typeof(object[]));
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldstr, srcEvent.Name);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldc_I4, parameterTypes.Length - 1);
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc_0);
for (int j = 0; j < parameterTypes.Length - 1; j++)
{
Type parameter = parameterTypes[j];
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, j);
il.Emit(OpCodes.Ldarg, j + 1);
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_0);
MethodInfo eventReceivedMethod = this.GetType().GetMethod("EventReceived", BindingFlags.Public | BindingFlags.Instance);
il.EmitCall(OpCodes.Callvirt, eventReceivedMethod, null);
il.Emit(System.Reflection.Emit.OpCodes.Ret);
srcEvent.AddEventHandler(srcObject, handler.CreateDelegate(srcEvent.EventHandlerType, this));
}
}
private Type[] GetDelegateParams(Type d)
{
MethodInfo delegateMethod = d.GetMethod("Invoke");
ParameterInfo[] delegateParams = delegateMethod.GetParameters();
Type[] result = new Type[delegateParams.Length + 1];
result[0] = this.GetType();
for (int i = 0; i < delegateParams.Length; i++)
{
result[i + 1] = delegateParams[i].ParameterType;
}
return result;
}
}
You could use reflection to get all the events of the object and hook them all into a debug method of yours.
void HookAllEvents(object obj)
{
foreach (var evInfo in obj.GetType().GetEvents())
{
evInfo.AddEventHandler(obj, new EventHandler(DebugEventHandler));
}
}
void DebugEventHandler(object sender, EventArgs e)
{
}
Don't forget to unhook at the end :)
You can't do this automatically.
However, if you're just trying to figure out which events get fired when, try Spy++.
精彩评论