読者です 読者をやめる 読者になる 読者になる

いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

動的にイベントを追加・削除する。(EventHandler, Delegate.CreateDelegate, EventInfo, AddEventHandler, RemoveEventHandler)


たまに動的にイベントを追加したり、削除したりしたいときがあります。
イベントを動的に追加・削除するには以下のクラスを利用します。

  • System.Delegate
  • System.Reflection.EventInfo


面倒なのが、実際にイベントを追加したり削除したりする際です。
いくら文字列で処理が実装されているメソッド名をもっていても
MethodInfoでは追加できません。一旦、該当するイベントのイベントハンドラデリゲート
でラップする必要があります。


動的にデリゲートを作成するには、以下のようにします。

Delegate d = Delegate.CreateDelete(イベントハンドラのタイプ, 処理メソッドを持つオブジェクト, メソッド名もしくはMethodInfo);


上記のを組み合わせると動的にイベントを追加・削除できます。
以下サンプルです。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Reflection;
using System.Windows.Forms;

namespace Gsf.Demo{

    public class DemoForm : Form{

        Button btn1;
        Button btn2;
        Button btn3;

        public DemoForm(){
            InitializeComponent();
            InitializeEventBinding();
        }

        protected void InitializeComponent(){

            SuspendLayout();

            Text = "動的にイベントを追加するサンプル";

            btn1 = new Button();
            btn1.Text = "イベント追加";

            btn2 = new Button();
            btn2.Text = "イベント削除";

            btn3 = new Button();
            btn3.Text = "イベント実行";

            FlowLayoutPanel p = new FlowLayoutPanel();
            p.Controls.AddRange(new []{btn1, btn2, btn3});

            Controls.Add(p);

            ResumeLayout();
        }

        protected void InitializeEventBinding(){
            //
            // 通常のイベントバインディング.
            //
            btn1.Click += AddEvent;

        }

        public void AddEvent(object sender, EventArgs e){
            //
            // イベントを動的に追加する。
            //
            Type handlerType = typeof(EventHandler);

            Action<Control, string> registEvent = (ctl, methodName) => {
                //
                // 該当するイベントのイベントハンドラを構築し、追加する。
                // (今回はサンプルなのでmethodNameに指定したメソッドはスコープをpublicにしています。
                //  実際は、フォーム内に定義されているメソッドはprivateなどで定義するべきです。)
                //
                Delegate eventMethod = 
                    Delegate.CreateDelegate(handlerType, this, this.GetType().GetMethod(methodName));

                ctl.GetType().GetEvent("Click").AddEventHandler(ctl, eventMethod);
            };

            registEvent(btn2, "RemoveEvent");
            registEvent(btn3, "ExecuteEvent");

        }

        public void RemoveEvent(object sender, EventArgs e){
            //
            // イベントを動的に削除する。
            //
            Type handlerType = typeof(EventHandler);

            Action<Control, string> removeEvent = (ctl, methodName) => {
                //
                // 該当するイベントのイベントハンドラを構築し、削除する。
                // (今回はサンプルなのでmethodNameに指定したメソッドはスコープをpublicにしています。
                //  実際は、フォーム内に定義されているメソッドはprivateなどで定義するべきです。)
                //
                Delegate eventMethod = 
                    Delegate.CreateDelegate(handlerType, this, this.GetType().GetMethod(methodName));

                ctl.GetType().GetEvent("Click").RemoveEventHandler(ctl, eventMethod);
            };

            removeEvent(btn2, "RemoveEvent");
            removeEvent(btn3, "ExecuteEvent");
        }

        public void ExecuteEvent(object sender, EventArgs e){
            MessageBox.Show("Execute Event.");
        }

        static void Main(){
            Application.EnableVisualStyles();
            Application.Run(new DemoForm());
        }
    }
}


上記のサンプルをコンパイルして実行すると、ボタンが表示されます。
イベントを追加ボタンを押下するまでは、その他のボタンを押下しても
何も反応しません。イベント追加ボタン押下後にイベント実行ボタンを
押下するとメッセージボックスが表示されます。



================================
過去の記事については、以下のページからご参照下さい。