2009-03-18 2 views
25

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

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

ответ

29

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

Событие является часто при поддержке частной сфере - но не с контролем; они используют подход 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); 
     } 
    } 
} 
+0

Прохладительность. Спасибо за быстрый ответ, Марк! – JoshL

+0

В тот день, когда я размышлял в Reflector, я понял, что это то же самое. –

+1

У меня была такая же потребность; в 'Control', идентифицирующие ключи называются в моде, например' EventMouseDown', а не 'EVENT_MOUSEDOWN', поскольку они предназначены для' Form'. –

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 в свой собственный обработчик.