トップ回答者
項目を動的に追加する時のイベントハンドラ

質問
回答
-
本筋ではありませんが、気になったので少しコメントしておきます。
private void AddedToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(string.Format("「{0}」がクリックされたよ!", (sender as ToolStripItem).Name)); }
as 演算子を使っている割に、キャストが失敗する(null を返す)ことを考慮していないというコードになっています。
必ずキャストに成功する前提であれば、キャスト式を用いて、((ToolStripItem)sender) とすることを提案します。元のコードでは、万が一キャストに失敗すると NullReferenceException になりますが、キャスト式の場合は InvalidCastException になります。
後者の方が失敗の原因に近い例外が出るという意味では、ベターではないかと考えています。(あくまで私の意見です)
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 回答としてマーク 村尾DOS 2011年5月22日 2:22
-
たとえば、
イベントハンドラを共有するために追加されたアイテムのうち、どれがクリックされたのかを知りたい
というシナリオの場合、
インデックスで管理するより名前で管理した方が保守的に楽でしょう。
その場合、前回の回答のメソッドでなく、
ToolStripItemCollection.Add メソッド (ToolStripItem)
こちらの方を使用して、名前をつけたアイテムのインスタンスを追加するという感じになるかと思います。
例)private void button1_Click(object sender, EventArgs e) { //メニューアイテムのインスタンスを作成し、諸々の設定をする。(一意な名前を必ずつける) var item = new ToolStripMenuItem( "追加されたメニューの表示テキスト", null, AddedToolStripMenuItem_Click ) { Name = "一意な名前をつけてね" }; //メニューにメニューアイテムを追加する。 contextMenuStrip1.Items.Add(item); } private void AddedToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(string.Format("「{0}」がクリックされたよ!", (sender as ToolStripItem).Name)); }
よろしくお願い致します。
- 回答としてマーク 村尾DOS 2011年5月22日 2:22
すべての返信
-
こんにちは。
動的に追加したメニューにクリックイベントを登録したいってことですよね?
でしたら
ToolStripItemCollection.Add メソッド (String, Image, EventHandler)
を使用します。
例)contextMenuStrip1.Items.Add( "追加されたメニューの表示テキスト", null, (s, ea) => { MessageBox.Show("追加されたメニューが押されたよ"); } );
上記はイベントハンドラをその場で定義していますが、別メソッドにしてもOKです。
以上、参考になりましたら幸いです。
-
たとえば、
イベントハンドラを共有するために追加されたアイテムのうち、どれがクリックされたのかを知りたい
というシナリオの場合、
インデックスで管理するより名前で管理した方が保守的に楽でしょう。
その場合、前回の回答のメソッドでなく、
ToolStripItemCollection.Add メソッド (ToolStripItem)
こちらの方を使用して、名前をつけたアイテムのインスタンスを追加するという感じになるかと思います。
例)private void button1_Click(object sender, EventArgs e) { //メニューアイテムのインスタンスを作成し、諸々の設定をする。(一意な名前を必ずつける) var item = new ToolStripMenuItem( "追加されたメニューの表示テキスト", null, AddedToolStripMenuItem_Click ) { Name = "一意な名前をつけてね" }; //メニューにメニューアイテムを追加する。 contextMenuStrip1.Items.Add(item); } private void AddedToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(string.Format("「{0}」がクリックされたよ!", (sender as ToolStripItem).Name)); }
よろしくお願い致します。
- 回答としてマーク 村尾DOS 2011年5月22日 2:22
-
本筋ではありませんが、気になったので少しコメントしておきます。
private void AddedToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(string.Format("「{0}」がクリックされたよ!", (sender as ToolStripItem).Name)); }
as 演算子を使っている割に、キャストが失敗する(null を返す)ことを考慮していないというコードになっています。
必ずキャストに成功する前提であれば、キャスト式を用いて、((ToolStripItem)sender) とすることを提案します。元のコードでは、万が一キャストに失敗すると NullReferenceException になりますが、キャスト式の場合は InvalidCastException になります。
後者の方が失敗の原因に近い例外が出るという意味では、ベターではないかと考えています。(あくまで私の意見です)
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。- 回答としてマーク 村尾DOS 2011年5月22日 2:22
-
>Azuleanさん
こんにちは。
ご指摘ありがとうございます。
昔所属していたPJのコーディングルールに、
「参照型のキャストはas演算子を使うべし。理由はパフォーマンスが良いから」
というものがあり、どっちでも良い場合(必ずキャストに成功する前提の場合)
無意識のうちにasを使って書いていたようです。
今、本当にパフォーマンスが良いのか調べ直してみましたら
演算子を使った式単体ですとそんなに変わらないようでした。
# 100000回ループで
# asは 00:06:40.0118794
# ()は 00:06:55.3677577
おそらく、そのコーディングルールを作成した人は
■@IT:.NET TIPS as演算子とキャストの違いは? - C#(ずいぶんと古い記事ですが)
http://www.atmarkit.co.jp/fdotnet/dotnettips/005castandas/castandas.html
の結果だけ見て書いたのではないかと、今になって考えました。
(所属していた時に気づけば良かったですが。。。)
パフォーマンスに違いがあまりないなら、
必ずキャストに成功する前提ならばAzuleanさんのおっしゃるとおり、
() 演算子を使った方が万々が一変な型を入れられた時の例外情報の観点から合理的ですね。
考えるきっかけを与えてくださって大変ありがとうございました。 -
>渋木さん
ありがとうございます。
私の質問にも舌足らずな部分があったようですみません。
>普通にRemoveメソッドで削除すればよい
は、
ContextMenuStrip.ItemsのRemoveメソッドのつもりでした。
>イベントハンドラを直接ラムダ式や匿名デリゲートで記述するとイベント接続が解除不能
ということは知っています。
が、
・サンプルの性格上、できるだけコードを短くしようという考え方があった
という理由により、上記サンプルのように書きました。
そこで、
>動的に追加した項目を、あとで動的に削除する場合、動的に接続したイベントを解除する必要があります。
の投稿をされたので、「なぜ動的に接続したイベントを解除する必要があるのだろう?」と疑問に思った次第です。
渋木さんも書いておられますが、常にイベントを解除する必要はないですよね。
(ソースがリスナより寿命が短い場合はソースもろとも消滅してくれれば良いので)