質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

31404閲覧

C#, EventHandlerの多重登録回避について教えてください。

meshkit

総合スコア72

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2018/01/31 01:43

前提・実現したいこと

EventHandlerの登録について教えてください。
Windows Formアプリケーションを作っています。
EventHandlerをコードで登録する場合、繰り返し登録すると、イベントハンドラは多重登録できます。

試したこと

たとえば下記のコードでButton1をクリックすると、Button2のイベントハンドラを多重登録します。
Button1を1回クリック、Button2を1回クリック。-MessageBoxを1回表示。内容は1。
Button1を2回クリック、Button2を1回クリック。-MessageBoxを2回表示。内容は1,2。
Button1を3回クリック、Button2を1回クリック。-MessageBoxを3回表示。内容は1,2,3。

該当のソースコード

C#

1using System; 2using System.Windows.Forms; 3 4namespace WindowsFormsApplication1 5{ 6 public partial class Form1 : Form 7 { 8 public Form1() 9 { 10 InitializeComponent(); 11 } 12 13 private void button1_Click(object sender, EventArgs e) 14 { 15 counter = 0; 16 //if (this.button2.Click==null) 17 this.button2.Click += new System.EventHandler(this.button2_Click); 18 } 19 20 int counter = 0; 21 private void button2_Click(object sender, EventArgs e) 22 { 23 counter++; 24 MessageBox.Show(counter.ToString()); 25 } 26 } 27}

C#

1namespace WindowsFormsApplication1 2{ 3 partial class Form1 4 { 5 /// <summary> 6 /// 必要なデザイナー変数です。 7 /// </summary> 8 private System.ComponentModel.IContainer components = null; 9 10 /// <summary> 11 /// 使用中のリソースをすべてクリーンアップします。 12 /// </summary> 13 /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param> 14 protected override void Dispose(bool disposing) 15 { 16 if (disposing && (components != null)) 17 { 18 components.Dispose(); 19 } 20 base.Dispose(disposing); 21 } 22 23 #region Windows フォーム デザイナーで生成されたコード 24 25 /// <summary> 26 /// デザイナー サポートに必要なメソッドです。このメソッドの内容を 27 /// コード エディターで変更しないでください。 28 /// </summary> 29 private void InitializeComponent() 30 { 31 this.button1 = new System.Windows.Forms.Button(); 32 this.button2 = new System.Windows.Forms.Button(); 33 this.SuspendLayout(); 34 // 35 // button1 36 // 37 this.button1.Location = new System.Drawing.Point(207, 168); 38 this.button1.Name = "button1"; 39 this.button1.Size = new System.Drawing.Size(75, 23); 40 this.button1.TabIndex = 0; 41 this.button1.Text = "button1"; 42 this.button1.UseVisualStyleBackColor = true; 43 this.button1.Click += new System.EventHandler(this.button1_Click); 44 // 45 // button2 46 // 47 this.button2.Location = new System.Drawing.Point(146, 99); 48 this.button2.Name = "button2"; 49 this.button2.Size = new System.Drawing.Size(75, 23); 50 this.button2.TabIndex = 1; 51 this.button2.Text = "button2"; 52 this.button2.UseVisualStyleBackColor = true; 53 // 54 // Form1 55 // 56 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 57 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 58 this.ClientSize = new System.Drawing.Size(284, 261); 59 this.Controls.Add(this.button2); 60 this.Controls.Add(this.button1); 61 this.Name = "Form1"; 62 this.Text = "Form1"; 63 this.ResumeLayout(false); 64 65 } 66 67 #endregion 68 69 private System.Windows.Forms.Button button1; 70 private System.Windows.Forms.Button button2; 71 } 72}

発生している問題・エラーメッセージ

これを回避するために、

C#

1 if (this.button2.Click==null) 2 this.button2.Click += new System.EventHandler(this.button2_Click);
としたところ、 イベントControl.Clickは+=または-=の左側にのみ使用できます。 とエラーになります。 EventHandlerをコードで登録する場合、多重登録を回避する方法を知りたいです。 よろしくお願いします。

補足情報(FW/ツールのバージョンなど)

Visual Studio 2015 Pro
C#

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mattn

2018/01/31 01:50

多重登録された場合、先の物を生かすのでしょうか?それとも先の物を取り消し後の物を有効にするのでしょうか?
meshkit

2018/01/31 02:22

先のものを生かします。
guest

回答2

0

mattin さんが書かれているようにイベントの add, remove を明示的に実装すれば制御できます。

もし、同じメソッドが重複して登録されないようにしたいのであれば、add に渡された value からそのメソッドのクラス名やメソッド名を取得できます。

既に登録されているメソッドは GetInvocationList で取得できます。
mattin さんの例示コードでは fireEvent.GetInvocationList() です。Delegate の配列が取得できますので、EventHandler にキャストしてください。

とはいえ、イベントハンドラは初期処理やフォームデザイナで定義しておいて、

・その処理を実行するかどうかを制御するフラグを設ける。既定値は無効。
・フラグが有効でない場合は何もしない。
・button2 がクリックされたときにそのフラグを有効にする。

としたほうがよいような気がします。

投稿2018/01/31 04:09

masa_n

総合スコア110

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meshkit

2018/01/31 04:15

ありがとうございます。mattinさんの回答、なるほどと思ったものの、実際にはbuttonではなくハードウェアからやってくるイベントで、ちょっと現在のわたしには参考にはなるものの実装は無理とあきらめてました。 フラグ方式ならわたしにも使えそうです。こちらでやってみます。ありがとうございます。感謝。
guest

0

ベストアンサー

イベントハンドラを自前で実装すれば出来なくないです。

csharp

1using System; 2using System.Linq; 3 4class Publisher 5{ 6 private event EventHandler fireEvent; 7 8 public event EventHandler FireEvent 9 { 10 add 11 { 12 if (fireEvent == null) 13 { 14 fireEvent += value; 15 } 16 else 17 { 18 Console.WriteLine("重複登録ですよ"); 19 } 20 } 21 remove 22 { 23 fireEvent -= value; 24 } 25 } 26 27 public void Fire() 28 { 29 OnFire(new EventArgs()); 30 } 31 32 protected virtual void OnFire(EventArgs e) 33 { 34 if (fireEvent != null) 35 fireEvent(this, e); 36 } 37} 38 39public class Program 40{ 41 static void Main(string[] args) 42 { 43 var publisher = new Publisher(); 44 publisher.FireEvent += (o, e) => 45 { 46 Console.WriteLine("fire event!"); 47 }; 48 publisher.FireEvent += (o, e) => 49 { 50 Console.WriteLine("more fire event!"); 51 }; 52 publisher.Fire(); 53 } 54}

ただしコントロールの Click 等はこれが実装されてはいませんので継承するなりしてカスタムコントロール化しないといけないかもしれません。

投稿2018/01/31 02:55

mattn

総合スコア5030

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問