2009-03-18 1 views
25

J'ai un formulaire WinForms qui ne se ferme pas. Dans OnFormClosing, e.Cancel est défini sur true. Je suppose qu'un objet de mon application s'est lié à l'événement Closing ou FormClosing et bloque la fermeture. Pour le savoir, j'aimerais savoir quels délégués sont liés à l'un de ces événements.Déterminer la liste des gestionnaires d'événements liés à l'événement

Existe-t-il un moyen de déterminer la liste des gestionnaires liés à un événement? Idéalement, je le ferais via le débogueur Visual Studio, mais je peux écrire du code dans l'application pour trouver les gestionnaires si nécessaire. Comprendre qu'un événement est comme un champ privé caché, j'ai navigué à travers le débogueur vers les "champs non-publics" pour l'ancêtre "Windows.Forms.Form" de mon formulaire, mais en vain.

Répondre

29

En bref, vous n'êtes pas censé le faire - mais à des fins de débogage ...

Un événement est souvent soutenu par un champ privé - mais pas avec des contrôles; ils utilisent l'approche EventHandlerList. Vous devez accéder au membre Events protégé du formulaire, en recherchant l'objet mappé à l'objet (privé) EVENT_FORMCLOSING. Une fois que vous avez le FormClosingEventHandler, GetInvocationList devrait faire le travail.


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

Fraîcheur. Merci pour la réponse rapide, Marc! – JoshL

+0

Je creusais dans Reflector l'autre jour en pensant exactement à la même chose. –

+1

J'avais le même besoin; dans 'Control', les clés d'identification sont nommées comme' EventMouseDown' plutôt que 'EVENT_MOUSEDOWN' comme elles le sont pour' Form'. –

1

Le problème est peut-être que la forme ne valide pas.

L'événement FormClosing est soulevée par la méthode WmClose privé dans Form, initialisant e.Cancel-!Validate(true). Je n'ai pas enquêté, mais dans certaines circonstances, Validate retournera toujours false, ce qui entraînera l'annulation de la fermeture indépendamment des gestionnaires d'événements.

Pour étudier cette question, permettre .Net source debugging, mettre un point d'arrêt dans votre gestionnaire FormClosing, aller à la source pour Form.WmClose (la pile d'appel), mettre un point d'arrêt au début de WmClose, et fermez le formulaire. Ensuite, parcourez-le dans le débogueur et voyez pourquoi Validate renvoie false. (Ou quel gestionnaire d'événements définit e.Cancel à true)

Pour résoudre le problème, définissez e.Cancel sur false dans votre propre gestionnaire.