确定绑定到事件的事件处理程序列表

时间:2009-03-18 23:24:31

标签: c# visual-studio-2008 debugging events

我有一个不会关闭的WinForms表单。在OnFormClosing中,e.Cancel设置为true。我猜我的应用程序中的某些对象已绑定到Closing或FormClosing事件,并阻止关闭。为了找到答案,我想确定哪些代表与其中一个事件绑定。

有没有办法确定绑定到事件的处理程序列表?理想情况下,我会通过Visual Studio调试器执行此操作,但可以在应用程序中编写代码以在必要时查找处理程序。理解一个事件就像一个隐藏的私有字段,我已经通过调试器导航到我的表单的“Windows.Forms.Form”祖先的“非公共字段”,但无济于事。

2 个答案:

答案 0 :(得分:32)

简而言之,您并不打算这样做 - 但是出于调试目的......

事件经常由私人字段支持 - 但不包含控件;他们使用EventHandlerList方法。您必须访问表单的受保护Events成员,查找映射到(私有)EVENT_FORMCLOSING对象的对象。

获得FormClosingEventHandler后,GetInvocationList应该完成这项工作。


using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;
class MyForm : Form
{
    public MyForm()
    { // assume we don't know this...
        Name = "My Form";
        FormClosing += Foo;
        FormClosing += Bar;
    }

    void Foo(object sender, FormClosingEventArgs e) { }
    void Bar(object sender, FormClosingEventArgs e) { }

    static void Main()
    {
        Form form = new MyForm();
        EventHandlerList events = (EventHandlerList)typeof(Component)
            .GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(form, null);
        object key = typeof(Form)
            .GetField("EVENT_FORMCLOSING", BindingFlags.NonPublic | BindingFlags.Static)
            .GetValue(null);

        Delegate handlers = events[key];
        foreach (Delegate handler in handlers.GetInvocationList())
        {
            MethodInfo method = handler.Method;
            string name = handler.Target == null ? "" : handler.Target.ToString();
            if (handler.Target is Control) name = ((Control)handler.Target).Name;
            Console.WriteLine(name + "; " + method.DeclaringType.Name + "." + method.Name);
        }
    }
}

答案 1 :(得分:1)

问题可能是表单无法验证。

FormClosing事件由WmClose中的私有Form方法引发,该方法将e.Cancel初始化为!Validate(true)。我没有调查过,但在某些情况下,Validate将始终返回false,导致无论是否有任何事件处理程序都会取消关闭。

要调查此问题,请启用.Net source debugging,在FormClosing处理程序中放置一个断点,转到Form.WmClose的源代码(调用堆栈上方),在开头的位置放置一个断点WmClose,然后再次关闭表单。然后,在调试器中逐步执行它,看看Validate返回false的原因。 (或者哪个事件处理程序将e.Cancel设置为true)

要解决此问题,请在您自己的处理程序中将e.Cancel设置为false