2009-03-18 16 views
25

Mam formularz WinForm, który nie zostanie zamknięty. W OnFormClosing, e.Cancel ma wartość true. Zgaduję, że niektóre obiekty w mojej aplikacji zostały powiązane z wydarzeniem Zamknięcie lub FormClosing i blokują zamknięcie. Aby się tego dowiedzieć, chciałbym określić, którzy uczestnicy są związani z jednym z tych wydarzeń.Określenie listy programów obsługi zdarzeń związanych z zdarzeniem

Czy istnieje sposób określenia listy procedur obsługi związanych z wydarzeniem? Najlepiej byłoby zrobić to za pomocą debugera Visual Studio, ale można napisać kod w aplikacji, aby znaleźć programy obsługi, jeśli to konieczne. Zrozumienie, że zdarzenie jest jak ukryte prywatne pole, przeszukałem Debugger do "niepublicznych pól" dla przodka "Windows.Forms.Form" mojego formularza, ale bezskutecznie.

Odpowiedz

29

W skrócie, nie jesteś oznaczało to zrobić - ale dla celów debugowania ...

Zdarzenie jest często poparte prywatnym polu - ale nie z kontroli; używają podejścia EventHandlerList. Będziesz musiał uzyskać dostęp do chronionego formularza Events, szukając obiektu zmapowanego do (prywatnego) obiektu EVENT_FORMCLOSING.

Po utworzeniu FormClosingEventHandler, GetInvocationList powinno wykonać zadanie.


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

Chłodzenie. Dzięki za szybką odpowiedź, Marc! – JoshL

+0

Pewnego dnia kopałem w Reflectorze, wymyślając dokładnie to samo. –

+1

Miałem taką samą potrzebę; w 'Control', klucze identyfikacyjne są nazywane w modzie jak' EventMouseDown' zamiast 'EVENT_MOUSEDOWN', tak jak w przypadku' Form'. –

1

Problemem może być to, że forma nie sprawdza.

Impreza FormClosing jest podnoszona przez prywatnego WmClose metody w Form, który inicjuje e.Cancel do !Validate(true). Nie badałem, ale w pewnych okolicznościach Validate zawsze zwróci false, powodując zakończenie zamykania bez względu na jakiekolwiek procedury obsługi zdarzeń.

Aby to zbadać, włącz .Net source debugging, umieścić punkt przerwania w obsługi FormClosing, przejdź do źródła dla Form.WmClose (do stosu wywołań), umieścić punkt przerwania na początku WmClose i ponownie zamknąć formularz. Następnie przejdź przez niego do debuggera i zobacz, dlaczego powraca Validate . (Lub która funkcja obsługi zdarzenia ustawiona jest na e.Cancel).

Aby rozwiązać problem, ustaw e.Cancel na false w swojej własnej procedurze obsługi.

Powiązane problemy