web-dev-qa-db-ja.com

イベントにバインドされたイベントハンドラーのリストを決定する

閉じないWinFormsフォームがあります。 OnFormClosingでは、e.Cancelがtrueに設定されています。アプリケーションの一部のオブジェクトがClosingイベントまたはFormClosingイベントにバインドされ、クローズをブロックしていると思います。調べるために、これらのイベントの1つにバインドされているデリゲートを特定したいと思います。

イベントにバインドされたハンドラーのリストを決定する方法はありますか?理想的には、Visual Studioデバッガーを使用してこれを行いますが、必要に応じて、アプリケーションでコードを記述してハンドラーを見つけることができます。イベントが非表示のプライベートフィールドのようなものであることを理解して、デバッガーを使用して、フォームの「Windows.Forms.Form」祖先の「非パブリックフィールド」に移動しましたが、役に立ちませんでした。

29
JoshL

要するに、あなたはこれをするつもりはありません-しかし、デバッグ目的のために...

イベントは多くの場合プライベートフィールドによってサポートされますが、コントロールではサポートされません。彼らはEventHandlerListアプローチを使用しています。 (プライベート)EVENT_FORMCLOSINGオブジェクトにマップされたオブジェクトを探して、フォームの保護されたEventsメンバーにアクセスする必要があります。

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);
        }
    }
}
32
Marc Gravell

問題は、フォームが検証されないことかもしれません。

FormClosingイベントは、WmCloseのプライベートFormメソッドによって発生し、_e.Cancel_を!Validate(true)に初期化します。私は調査していませんが、特定の状況では、Validateは常にfalseを返し、イベントハンドラーに関係なくクローズがキャンセルされます。

これを調査するには、 。Netソースデバッグ を有効にし、FormClosingハンドラーにブレークポイントを置き、_Form.WmClose_のソースに移動します(コールスタックを上に移動)、ブレークポイントを置きますWmCloseの先頭で、フォームをもう一度閉じます。次に、デバッガーでそれをステップ実行し、Validatefalseを返す理由を確認します。 (または_e.Cancel_をtrueに設定しているイベントハンドラー)

この問題を解決するには、独自のハンドラーで_e.Cancel_をfalseに設定します。

1
SLaks