ここから本文です

C# イベントハンドラ ソース簡略化

sky********さん

2009/12/921:37:20

C# イベントハンドラ ソース簡略化

WindowFormでロード時に配列を使ってボタンを5つ生成しました。

それぞれのクリックイベントハンドラを追加した時イベントハンドラは

this.button[0].Click += new System.EventHandler(this.button0_Click);
this.button[1].Click += new System.EventHandler(this.button1_Click);
this.button[2].Click += new System.EventHandler(this.button2_Click);
this.button[3].Click += new System.EventHandler(this.button3_Click);
this.button[4].Click += new System.EventHandler(this.button4_Click);

という感じで書いて追加したのですが、

これをforのループを使ってソースを簡略化しようとしたのですが、右の「button0_Click」の所が
エラーになってしまいうまくいきません。

この部分のソースの簡略化は可能でしょうか。あればご教授お願い致します。

補足回答ありがとうございます。

自分のやりたい事は、5つの要素がある配列(a[0]~a[4])に
全て違う文字列(URL)が入っていて
ボタンをクリックするとそれぞれのURLを開くという感じです。

一番下のコードを使ってこういう事に応用はできますでしょうか

閲覧数:
778
回答数:
2
お礼:
25枚

違反報告

ベストアンサーに選ばれた回答

ttkai00さん

編集あり2009/12/1016:53:19

リフレクションを使ってやろうと思えばできます。

一例ですが、フォームに以下のようなメソッドを定義して(要:using System.Reflection)

private void addClickHandler(Button targetButton, String handlerName)
{
EventInfo ev = typeof(Button).GetEvent("Click");

MethodInfo mi = this.GetType().GetMethod(handlerName,
BindingFlags.NonPublic | BindingFlags.Instance);

Delegate d = Delegate.CreateDelegate(
ev.EventHandlerType, this, mi);

MethodInfo addHandler = ev.GetAddMethod();

addHandler.Invoke(targetButton,
new object[] { d });
}

以下のようなループにすればできます。

for (int i = 0; i < 5; i++)
addClickHandler(button[i], "button" + i.ToString() + "_Click");

と、ソースまで出しておいてなんですが、これは無理と回答されたので反応しただけです。質問者さんはやらない方がいいでしょう。

質問者さんが作っているものの仕様はわかりませんけど、こんな方法でないと実現できない仕様ってそう多くありません。多くの場合は別の方法で解決できると思いますし、そちらの方がスマートで高速に動作するでしょう。(リフレクションは遅いです)

たぶん1つのハンドラにできるんじゃないですか?イベントハンドラは複数のボタンに関連づけられてもいいわけですから。

for (int i = 0; i < 5; i++)
button[i].Click += this.button_Click;

private void button_Click(object sender, EventArgs e)
{
// sender から押されたボタンを取得できる
Button senderButton = sender as Button;

// もしインデックスが欲しいなら、こうやって取得できる
int senderIndex = button.IndexOf(senderButton);

// 何か処理をする
}

これならボタンが増えても、イベントハンドラを増やす必要もないですし。

※補足を受けて

URL配列のインデックスとボタン配列のインデックスが、完全に一致している前提なら、上記コードのイベントハンドラ中で取得している senderIndex がそれにあたります。ですから

String url = a[senderIndex];

で URL を取得できますよね。

あとはお好きな方法でこれを開けばよいでしょう。何で開くのか書いていないのでわかりませんが、例えば普通にブラウザで開くなら

Process.Start(url)

とか。

※f_sasaki0 さん

まあこの程度のところで、リフレクションを持ち出すのは、確かに手段を選んでいないといってもよいかも知れませんね。

ただ、本当にリフレクションしかないケースというのもありますので、検索して来られる方の参考になればと思って、一応提示してみただけです。

それから、イベントとイベントハンドラの関係は多対多です。1つのイベントハンドラを複数のイベントに関連付けることも可能ですし、1つのイベントに複数のイベントハンドラを関連付けることも可能です。(もちろんイベントハンドラの型が同じものに限りますが。)

私が「たぶん」と書いたのは、そこに自信がなかったからではなく、質問者さんの作っているアプリケーションの仕様がわからなかったからです。

※ソースが少しあやまっていたので修正しました。

※追記

他には、Tag プロパティを使うような手も、こういうケースでは考えられますね。ボタンにあらかじめ、以下のように Tag を設定しておけば、

for (int i = 0; i < 5; i++)
button[i].Tag = a[i];

イベントハンドラで、わざわざインデックスを取らなくても、Tag の URL を使用できます。

String url = (String)senderButton.Tag;

※f_sasaki0 さん

意図するところは理解しました。

こちらこそ、今後ともよろしくお願いします。

質問した人からのコメント

2009/12/10 18:54:06

お二方回答ありがとうございました。
試しにやってみた所なぜかエラーが出てしまったので、
再度質問して解決したいと思います。

ベストアンサー以外の回答

1〜1件/1件中

佐々木さん

編集あり2009/12/1015:15:51

C#の仕様上、無理だと思います。

>>この部分のソースの簡略化は可能でしょうか。
との、「この部分の」という限定つきの話でしたので、。。。

手段を選ばなければ、という前提での話までは、私の及ぶ範囲ではありません。

>>たぶん1つのハンドラにできるんじゃないですか?
>>イベントハンドラは複数のボタンに関連づけられてもいいわけですから。

本当ですか?
ttkai00さんの方法で実際に成功したのでしたら、教えて頂きたいと思います。

★仕様上、無理
と申し上げたのはC#のWindowsフォームアプリケーションの場合、
Form1.csがソースジェネレーションで作られ、プログラマが加筆し、
button1_Click()のbutton1の部分が「name」で変更不可能なので、
そのようなC#の仕様ならば、とても質問者の希望は無理と判断しました。
でも、私自身はC#構文解説書は以前から所持していますが、
今日2009/12/10生まれて初めて、
C#コンパイラをインストールした状態ですので、
詳細は理解出来ていません。今後とも宜しくお願いします。

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる