none
イベントの削除・入替方法は? RRS feed

  • 質問

  • 毎度、お世話に成ります。

     

    任意の関数をボタンのイベントに割り当てる事に挑んでいるのですが(実際にはボタンに割り当てる関数を外部で制御したい)

    イベントの削除方法がわからずに悩んでいます。

     

    サンプルコードです。

    コード ブロック

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Data.OleDb;
    using System.IO;
    using System.Reflection;

     

    namespace Test.TestForms
    {
     public partial class Form1 : Form
     {
      
      public Form1()
      {
       InitializeComponent();
      }

     

      public void Action1_Click(object sender, EventArgs e)
      {
       MessageBox.Show("1"); 
      }

      public void Action2_Click(object sender, EventArgs e)
      {
       MessageBox.Show("2"); 
      }

      public void Action3_Click(object sender, EventArgs e)
      {
       MessageBox.Show("3"); 
      }

      public void Action4_Click(object sender, EventArgs e)
      {
       MessageBox.Show("4"); 
      }

     

      private void Form1_Load(object sender, EventArgs e)
      {
       Type     type  = this.GetType();

       MethodInfo[] infos = type.GetMethods();

     

       // Action?_Clickの名称をlistBox1に追加

      foreach (MethodInfo info in infos)
       {
        if (info.Name.IndexOf("Action") >= 0 && info.Name.IndexOf("Click") > 0)
        {
         listBox1.Items.Add(info.Name);
        }
       }
      }

     

      private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
      {
       string s = listBox1.Items[listBox1.SelectedIndex] as string;

       Type       type = this.GetType();
       MethodInfo info = type.GetMethod(s);
       Delegate   Event = Delegate.CreateDelegate(typeof(EventHandler), this, s);

     

       // listBox1 で選択している名称のイベントを Button1 の Click に登録

       // 本当は此処で Button1.Click -= (????) で登録されているイベントを全部削除したい

       Button1.Click += Event as EventHandler;
      }
     }
    }

     

    実際にはイベント名をDB等に複数登録して置いてボタンをイベントランチャー的に使いたいのですが、Button1.Click に登録されているイベントが何が登録されているか判らないので、Button1.Click に登録されているものを全削除したいのです。

     

    何かヒントになるようなアドバイス頂けないでしょうか?

    よろしくお願い致します。

    2007年11月27日 10:06

回答

  • eventフィールドは+=か-=の操作しかできません。

    既存のeventを全て削除するためには、別途それらを記憶するフィールド変数が必要となると思います。

     

    今回ボタン1個につき1個のイベントを割り当てるという趣旨であれば、次のような形でどうでしょうか?

     

     

    コード ブロック
            private void Form1_Load(object sender, EventArgs e)
            {
                CurrentEvent = new EventHandler(Action2_Click);
            }
           
            private EventHandler CurrentEvent;
            private void button1_Click(object sender, EventArgs e)
            {
                if (CurrentEvent != null)
                {
                    CurrentEvent(sender, e);
                }
            }

     

     

    CurrentEventの値を差し替える形です。

    2007年11月27日 16:30
    モデレータ
  •  Nishizaka さんからの引用

    何かヒントになるようなアドバイス頂けないでしょうか?

     

    ちょっと前にVBの方にこんな過去スレッドがありました。

     

     MSDN フォーラム > Visual Studio > Visual Basic フォーラム > イベントの存在チェック 

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2091544&SiteID=7

     

    ご参考になりませんか。

    2007年11月27日 17:06
  • IIJIMAS さん コメントありがとうございます。

     IIJIMAS さんからの引用

     MSDN フォーラム > Visual Studio > Visual Basic フォーラム > イベントの存在チェック 

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2091544&SiteID=7

     

    すごく参考に成りました。ご紹介頂いたスレッドの

    http://www.technewsgroups.net/group/microsoft.public.dotnet.general/topic4196.aspx

     

    このEventDatum クラスを使い(エベント名を参照するプロパティを追加して)

    コード ブロック

     public class EventDatum
     {
       |

        public string EventName
        {
          get { return _event.Method.Name; }
        }

     }

     

     

    listBox1_SelectedIndexChanged を下記の様に書き換えることで

    コード ブロック

      private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
      {
        // ターゲットイベントの削除

       EventDescriptorCollection events = TypeDescriptor.GetEvents(this);
       foreach (System.ComponentModel.EventDescriptor myEvent in events)
       {
         EventDatum ed = EventDatum.Create(Button1, myEvent);
         if (ed == null) continue;
         if (ed.EventName.IndexOf("Action") >= 0 && ed.EventName.IndexOf("Click") > 0)
         { 
          ed.Unwire(Button1);
         }
       }

     

       string s = listBox1.Items[listBox1.SelectedIndex] as string;
       Delegate   Event = Delegate.CreateDelegate(typeof(EventHandler), this, s);

       Button1.Click += Event as EventHandler;
      }

     

     

    イベント関数名に一貫性を持たせれば、可能な事がわかりました。

    アドバイス、ありがとうございました。

    2007年11月28日 2:42

すべての返信

  • eventフィールドは+=か-=の操作しかできません。

    既存のeventを全て削除するためには、別途それらを記憶するフィールド変数が必要となると思います。

     

    今回ボタン1個につき1個のイベントを割り当てるという趣旨であれば、次のような形でどうでしょうか?

     

     

    コード ブロック
            private void Form1_Load(object sender, EventArgs e)
            {
                CurrentEvent = new EventHandler(Action2_Click);
            }
           
            private EventHandler CurrentEvent;
            private void button1_Click(object sender, EventArgs e)
            {
                if (CurrentEvent != null)
                {
                    CurrentEvent(sender, e);
                }
            }

     

     

    CurrentEventの値を差し替える形です。

    2007年11月27日 16:30
    モデレータ
  •  Nishizaka さんからの引用

    何かヒントになるようなアドバイス頂けないでしょうか?

     

    ちょっと前にVBの方にこんな過去スレッドがありました。

     

     MSDN フォーラム > Visual Studio > Visual Basic フォーラム > イベントの存在チェック 

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2091544&SiteID=7

     

    ご参考になりませんか。

    2007年11月27日 17:06
  • Azuleanさん コメントありがとうございます。

    >今回ボタン1個につき1個のイベントを割り当てるという趣旨であれば、次のような形でどうでしょうか?

     

    書き足りない部分があって申し訳ありません。実際にやりたいのはボタンは沢山(10~20個程度)に成り、DBで

    分類を選択したら、分類毎のデータによってボタンのTextを含めてガラガラと変わるようなものを考えています。

    なので出来るだけ汎用的に割り当てられているイベントを全削除して1個だけのイベントを登録したいのが目標です。

     

    IIJIMAS さんのアドバイスで、解決出来ました。

    2007年11月28日 2:31
  • IIJIMAS さん コメントありがとうございます。

     IIJIMAS さんからの引用

     MSDN フォーラム > Visual Studio > Visual Basic フォーラム > イベントの存在チェック 

    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2091544&SiteID=7

     

    すごく参考に成りました。ご紹介頂いたスレッドの

    http://www.technewsgroups.net/group/microsoft.public.dotnet.general/topic4196.aspx

     

    このEventDatum クラスを使い(エベント名を参照するプロパティを追加して)

    コード ブロック

     public class EventDatum
     {
       |

        public string EventName
        {
          get { return _event.Method.Name; }
        }

     }

     

     

    listBox1_SelectedIndexChanged を下記の様に書き換えることで

    コード ブロック

      private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
      {
        // ターゲットイベントの削除

       EventDescriptorCollection events = TypeDescriptor.GetEvents(this);
       foreach (System.ComponentModel.EventDescriptor myEvent in events)
       {
         EventDatum ed = EventDatum.Create(Button1, myEvent);
         if (ed == null) continue;
         if (ed.EventName.IndexOf("Action") >= 0 && ed.EventName.IndexOf("Click") > 0)
         { 
          ed.Unwire(Button1);
         }
       }

     

       string s = listBox1.Items[listBox1.SelectedIndex] as string;
       Delegate   Event = Delegate.CreateDelegate(typeof(EventHandler), this, s);

       Button1.Click += Event as EventHandler;
      }

     

     

    イベント関数名に一貫性を持たせれば、可能な事がわかりました。

    アドバイス、ありがとうございました。

    2007年11月28日 2:42