【问题标题】:Track (all) the events from a Control跟踪(所有)来自控件的事件
【发布时间】:2010-01-04 14:10:34
【问题描述】:

简单情况(VS2005,.NET2):I have a textBox1 on a panel1. I need to track all the emitted events from this textBox1.

实际上,当我需要从这个 textBox1 跟踪单个事件(TextChanged,例如)时,我会向(TextChanged 事件)添加一个处理程序,然后设置一个非阻塞 breakpoint 写入输出控制台包含函数(事件处理程序)名称的消息。 因此,对于单个事件,我可以编写此处理程序并设置断点,但我可以为所有可能的文本框(或其他控件)的事件做类似的事情吗?

alt text http://lh5.ggpht.com/_1TPOP7DzY1E/S0H5NHjXSjI/AAAAAAAAC24/tV0IiUsxwAU/s800/eventsTrack.png

更深入地讲,我需要知道在特定时刻在提到的控件(文本框)上发生了什么事件。

谢谢。

【问题讨论】:

    标签: .net visual-studio debugging events controls


    【解决方案1】:

    Aviad 的帖子是一个好的开始。您可以将它用于EventHandler 类型的事件。对于其他委托类型,您可以使用相同的技术为每种类型手动创建处理程序。

    如果您想更加灵活,您应该在运行时使用System.Reflection.Emit 创建事件处理程序。这里有详细解释:http://msdn.microsoft.com/en-us/library/ms228976.aspx。向下滚动到“使用动态方法在运行时生成事件处理程序”标题。

    //编辑

    我创建了一个简单的类,它能够处理特定对象的所有事件并将它们传递给通用事件处理程序。代码基于来自MicrosoftXTreme.NET Talk 的示例。

    基本思路

    • 在运行时创建与事件具有相同参数的方法
    • 将此方法设置为 Type.GetEvents() 中每个事件的事件处理程序
    • 从此方法调用通用事件处理程序

    用法

    要附加的对象在构造函数中传递。下一个UniversalEventHandler 类型的匿名方法用于处理所有事件。此方法接收事件名称为eventName,事件参数为args。您可以在此方法上设置断点并在 Visual Studio 中检查参数或自行打印它们。在此示例用法中,仅打印事件名称并可在“输出”窗口中找到(Visual Studio 中的菜单“视图”>“输出”)。在此示例中,标准按钮 button1 被检查。

    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);
    
    }
    

    代码

    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;
        }
    }
    

    【讨论】:

    • @Petr:首先,不幸的是,Aviad 方法对我不起作用(.NET 2),因为它无法转换“System.Windows.Forms”中的“System.EventHandler”。鼠标事件处理程序'。其次,我不需要生成一个事件,而是拦截它...
    • 很棒的课程!!在百万种场景中肯定有用。
    • Serhio:使用我编辑的答案中的代码,您可以拦截所有事件及其参数。 Aviad 的方法在 .NET 2.0 下适用于我,请尝试以下代码:this.GetType().GetEvent("KeyDown").AddEventHandler(this, (EventHandler)delegate(object src, EventArgs ev) { ... });它不会做任何事情,因为 KeyDown 不是 EventHandler,但它会毫无错误地编译。如果您将“KeyDown”更改为“Click”处理程序将被触发。希望这会有所帮助。
    • @Petr:是您自己的代码,还是“通用”实践? :) 这真的很有用,即使我什么都不懂
    • 我有了一个想法并开始编码。我在生成 IL 时遇到了一些问题,因此我使用了 XTreme.NET 中的一个并添加了 eventName 传递。所以这不全是我的。可以进行一些改进,例如为每个委托类型只创建一个方法。但是,为了完成工作,可以使用此方法。我考虑创建某种博客文章,我可以在其中更多地解释这段代码是如何工作的。如果发生这种情况,你想让我告诉你吗?
    【解决方案2】:

    您可以使用反射来获取对象的所有事件并将它们全部挂钩到您的调试方法中。

    void HookAllEvents(object obj)
    {
        foreach (var evInfo in obj.GetType().GetEvents())
        {
            evInfo.AddEventHandler(obj, new EventHandler(DebugEventHandler));
        }
    }
    
    void DebugEventHandler(object sender, EventArgs e)
    {
    }
    

    最后别忘了解开钩子:)

    【讨论】:

    • 这不适用于像KeyPress 这样不是EventHandlers 的事件。
    • 在我看来这是一个普通的事件处理程序。 msdn.microsoft.com/en-us/library/…
    • KeyPress 是 KeyPressEventHandler,而不是 EventHandler
    • 那么,我如何知道传递给 DebugEventHandler 的事件是什么? (不要忘记 .NET 2
    • 检查Environment.StackTrace
    【解决方案3】:

    您无法自动执行此操作。

    但是,如果您只是想弄清楚什么时候触发了哪些事件,请尝试 Spy++。

    【讨论】:

    • 它是拦截所有类型的事件,还是只拦截系统事件?
    • 显示 Windows 消息;几乎所有标准事件都直接映射到 Windows 消息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 2017-07-11
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    相关资源
    最近更新 更多