Определить список обработчиков событий, связанных с событием

У меня есть форма WinForms, которая не будет закрыта. В OnFormClosing для e.Cancel установлено значение true. Я предполагаю, что какой-то объект в моем приложении привязан к событию Закрытие или FormClosing и блокирует закрытие. Чтобы узнать, я хотел бы определить, какие делегаты связаны с одним из этих событий.

Есть ли способ определить список обработчиков, связанных с событием? В идеале я бы сделал это с помощью отладчика Visual Studio, но могу написать код в приложении, чтобы найти обработчики, если это необходимо. Понимая, что событие похоже на скрытое личное поле, я прошел через Debugger в "Непубличные поля" для предка "Windows.Forms.Form" моей формы, но безрезультатно.

Ответ 1

Короче говоря, вы не предназначены для этого, но для целей отладки...

Событие часто, поддерживаемое частным полем, но не с элементами управления; они используют подход EventHandlerList. Вам нужно будет получить доступ к элементу, защищенному формой Events, ищите объект, сопоставленный с объектом (private) 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);
        }
    }
}

Ответ 2

Проблема может заключаться в том, что форма не проверяется.

Событие FormClosing создается частным WmClose методом Form, который инициализирует e.Cancel до !Validate(true). Я не исследовал, но при определенных обстоятельствах Validate всегда будет возвращать false, в результате чего закрытие будет отменено независимо от каких-либо обработчиков событий.

Чтобы исследовать это, включите . Отладка исходного источника, поместите контрольную точку в обработчик FormClosing, перейдите к источнику для Form.WmClose (вверх по стеку вызовов), поставьте точку останова в начале WmClose и снова закройте форму. Затем пройдите через него в отладчике и посмотрите, почему Validate возвращает false. (Или какой обработчик события устанавливает e.Cancel в true)

Чтобы решить проблему, установите e.Cancel в false в свой собственный обработчик.