C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[26]: パネルコントロールに配置したラベルのクリックイベントの取得 [1]


(過去ログ 60 を表示中)

[トピック内 34 記事 (21 - 34 表示)]  << 0 | 1 >>

■34566 / inTopicNo.21)  Re[13]: パネルコントロールに配置したラベルのクリックイベントの取得
  
□投稿者/ 魔界の仮面弁士 (1031回)-(2009/04/01(Wed) 15:49:34)
No34563 (tamaboyo さん) に返信
>>> 継承先にもLB_Clickがあるため、継承先は継承先で宣言が必要かと思っていました。
>>そもそも、継承元の LB_Click は継承先に見せる必要はないのですから、
>>private にしておけば十分だと思いますよ。
>>protected にするのは、OnLbClicked メソッドの方です。
> 継承元と継承先に同じ名前の関数があり、どちらもラベルのクリックイベントで発生する場合で
> virtualとoverrideを利用する場合は、protectedではないのでしょうか?

継承元に protected な LB_Click メソッドがあった場合、
継承先で LB_Click メソッドを実装すると競合するため、
オーバーライド(override)かシャドウイング(new)かを選択せねばなりません。

しかし、継承元の実装が private void LB_Click(…) であるならば、
継承先で LB_Click メソッドを実装しても競合しません。何故なら継承先には、
継承元の private メンバの存在は見えないからです。


> この場合、継承元のLB_Clickのイベントはどうなるのでしょうか?

外から見えないだけであって、private メンバも内部には存在していますので、
処理は問題なく行われます。

もしも、Label.Click から LB_Click が呼び出されない仕様なのだとしたら、
同様に、Form.Load から Form1_Load も呼び出されない事になってしまいますが、
実際には、Load の処理なども行われていますよね。


>>そこで、個々のラベルに対してイベントを割り当てていくのでは無く、
>>複数のラベルからのイベントを一つに集約した独自イベントを作成し、継承先が
>> this.LbClicked += Form1_LbClicked;
>>とするだけで、たとえば
>>のようにして利用できるように設計した方が使い勝手がよいであろう……という話です。
>
> それぞれのラベルがクリックされた判別はできるのでしょうか?

継承先フォームのイメージコードとして、先ほど、

>> private void Form1_LbClicked(object sender, LbClickedEventArgs e)
>> {
>>  Label label = e.Label;
>> }

というサンプルを書きましたよね。この変数 label が、クリックされたラベルを表しています。



> #どういうコードを書けば良いかがまだわからないので、

継承元フォーム側の実装は、たとえばこうかな。

 private void LB_Click(object sender, EventArgs e)
 {
  // クリックされたラベルを取得。
  Label label = (Label)sender;

  //
  // 必要があれば、ここに任意の処理を記述。
  //

  // LbClicked イベントを発生させるために用意した
  // protected メソッドを呼び出す。
  OnLbClicked(new LbClickedEventArgs(label));
 }

 public event LbClickedEventHandler LbClicked;

 protected void OnLbClicked(LbClickedEventArgs e)
 {
  if (LbClicked != null) LbClicked(this, e);
 }


 public delegate void LbClickedEventHandler(object sender, LbClickedEventArgs e);
 public class LbClickedEventArgs : EventArgs
 {
  private Label label;
  public Label Labels { get { return label; } }
  public LbClickedEventArgs(Label label) { this.label = label; }
 }
引用返信 編集キー/
■34571 / inTopicNo.22)  Re[14]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (82回)-(2009/04/01(Wed) 17:35:59)
魔界の仮面弁士 さん、ありがとうございます。

> 継承元に protected な LB_Click メソッドがあった場合、
> 継承先で LB_Click メソッドを実装すると競合するため、
> オーバーライド(override)かシャドウイング(new)かを選択せねばなりません。
>
> しかし、継承元の実装が private void LB_Click(…) であるならば、
> 継承先で LB_Click メソッドを実装しても競合しません。何故なら継承先には、
> 継承元の private メンバの存在は見えないからです。

なるほどです。
どちらのLB_Click関数もprivate宣言にしました。


>>この場合、継承元のLB_Clickのイベントはどうなるのでしょうか?
>
> 外から見えないだけであって、private メンバも内部には存在していますので、
> 処理は問題なく行われます。
>
> もしも、Label.Click から LB_Click が呼び出されない仕様なのだとしたら、
> 同様に、Form.Load から Form1_Load も呼び出されない事になってしまいますが、
> 実際には、Load の処理なども行われていますよね。

なるほど、そういえばそうですね。


> >>そこで、個々のラベルに対してイベントを割り当てていくのでは無く、
> >>複数のラベルからのイベントを一つに集約した独自イベントを作成し、継承先が
> >> this.LbClicked += Form1_LbClicked;
> >>とするだけで、たとえば
> >>のようにして利用できるように設計した方が使い勝手がよいであろう……という話です。
>>
>>それぞれのラベルがクリックされた判別はできるのでしょうか?
>
> 継承先フォームのイメージコードとして、先ほど、
>
> >> private void Form1_LbClicked(object sender, LbClickedEventArgs e)
> >> {
> >>  Label label = e.Label;
> >> }
>
> というサンプルを書きましたよね。この変数 label が、クリックされたラベルを表しています。
>>#どういうコードを書けば良いかがまだわからないので、
>
> 継承元フォーム側の実装は、たとえばこうかな。

提示いただいたソースを継承元に組み込んでみました。
組み込み終了時点ではコンパイルは通り、継承元のLB_Clickには飛んできました。
#継承先のLB_Clickにはまだ飛んできません。
その後、継承元のLB_Clickの第2引数をEventArgs型からLbClickedEventArgs型に変更したところ、Arrange関数でくくりつけをしている
Lb[i].Click += new EventHandler(this.LB_Click);
がエラーになりました。
そこで
Lb[i].Click += new LbClickedEventHandler(LB_Click);
に変更したところ、「'LbClickedEventHandler'を型'System.EventHandler'に暗黙的に変換できません。」のエラーメッセージが表示されました。
>>複数のラベルからのイベントを一つに集約した独自イベントを作成
のためにくくりつけようとしたのですが、ひょっとして、くくりつけは必要ないのでしょうか?
#せっかく丁寧説明していただいているのにきちんと理解できなくて申し訳ありません。
引用返信 編集キー/
■34575 / inTopicNo.23)  Re[15]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1032回)-(2009/04/01(Wed) 20:43:15)
2009/04/01(Wed) 22:57:53 編集(投稿者)

No34571 (tamaboyo さん) に返信
> どちらのLB_Click関数もprivate宣言にしました。

継承先に LB_Click は不要です。作っても良いですがあまり意味は無いでしょう。

継承先では、Label.Click イベントを拾って LB_Click にて処理するのではなく、
継承元の LBClicked イベントを拾って、Form1_LbClicked にて処理するようにします。

No34556 でも、そのように書いていますよね。
>>> また、継承先に用意するのは、Label.Click イベントを受け取るための LB_Click ではなく、
>>> 継承元フォーム.LbClicked イベントを受け取るための Form1_LbClicked になります。


> 組み込み終了時点ではコンパイルは通り、継承元のLB_Clickには飛んできました。
> #継承先のLB_Clickにはまだ飛んできません。

イベント発生時に呼び出されるようにするためには、+= を使って、
対象イベントに関連付けねばならない事は御存知かと思います。

しかし、「+=」でセットしたのは、継承元の LB_Click だけであり、
継承先の LB_Click はセットしていませんよね。
ですから、継承先の LB_Click は呼ばれないのです。


「+=」でのセット作業そのものは、継承先で行っても継承元で行っても良いのですが、
継承元は「継承先の LB_Click」の存在を知る事ができませんから、今のままですと、
継承先の LB_Click を、継承先自身でセットする羽目になってしまうのです。

そしてそれが、先の No34556 に書いた

>>> 継承元で動的生成された個々のラベルそれぞれに対して、継承先が、
>>>  this.Controls[indexLabel].Click += LB_Click;
>>> を行わねばならなくなってしまい、

に繋がってきます。


それを解決する手法の一つとして、先の No34518 では、独自の「LabelClick イベント」を
作るように促しています。これは、クリック時の処理を継承先で実装するという作業において、
継承元で生成された個々の Label.Click に、継承先の LB_Click を直接割り当てるのではなく、
独自のイベントを通じてやりとりするという方法です。

# tamaboyo さんは、「LbClicked イベント」という名前で実装する事にされたようですが、
# この際、名前は LabelClick でも LbClicked でも構いません。


> その後、継承元のLB_Clickの第2引数をEventArgs型からLbClickedEventArgs型に変更したところ、
修正の方向が間違っています。

先の No34566 のサンプルを見ても、継承元 LB_Click の第2引数は、
LbClickedEventArgs ではなく EventArgs になっていますよね。

>>> 継承元フォーム側の実装は、たとえばこうかな。
>>>  private void LB_Click(object sender, EventArgs e)


Lable.Click イベントは、EventHandler デリゲート型の引数定義を持ちます。
すなわち、(object, EventArgs)ですので、第二引数は EventArgs です。
ですからイベントハンドラとなる LB_Click も、第二引数は EventArgs です。


一方、独自定義の LbClicked イベントは、LbClickedEventHandler デリゲート型です。
これは (object, LbClickedEventArgs) であり、第二引数は LbClickedEventArgs 型という定義ゆえ、
当然、イベントハンドラとなる Form1_LbClicked の第二引数も LbClickedEventArgs 型となります。


> Lb[i].Click += new EventHandler(this.LB_Click);
> がエラーになりました。
第2引数の型を変更したため、LB_Click の定義が EventHandler では無くなってしまったのです。

たとえば、
 this.FormClosing += new FormClosingEventHandler(Form1_FormClosing); // OK
 button1.Click += new EventHandler(button1_Click); // OK
 button1.Click += new EventHandler(Form1_FormClosing); // ★NG
で、★のコードがエラーになる事は想像できますか? それと同じ事です。
(Form1_FormClosing は、第二引数が EventArgs 型ではないのでエラーになる)


> そこで
> Lb[i].Click += new LbClickedEventHandler(LB_Click);
> に変更したところ
Label.Click が要求するイベントハンドルは EventHandler ですから、これも NG です。

こちらのエラーは、上記のパターンで言うと、
 this.FormClosing += new FormClosingEventHandler(Form1_FormClosing); // OK
 button1.Click += new EventHandler(button1_Click); // OK
 button1.Click += new FormClosingEventHandler(Form1_FormClosing); // ★NG
といった感じです。(Click イベントが要求するのは、EventHandler なイベントハンドラなので、
FormClosingEventHandler なイベントハンドラは受け入れられない)


> >>複数のラベルからのイベントを一つに集約した独自イベントを作成
> のためにくくりつけようとしたのですが、ひょっとして、くくりつけは必要ないのでしょうか?

括りつけは必要ですが、その相手を間違えています。


Label.Click イベントを発生させるのは、Label コントロールです。
それを LB_Click で受信しようとしているのが、継承元フォームです。

一方、継承元フォーム.LBClicked イベントを発生させるのは、継承元フォームです。
それを Form1_LbClicked で受信しようとしているのが、継承先フォームです。


つまり、括る相手は、
 継承元フォーム: ラベル.Click += new EventHandler(LB_Click);
 継承先フォーム: フォーム.LbClicked += new LbClickedEventHandler(Form1_LBClicked);
となります。「Lb[i].Click += new LbClickedEventHandler(LB_Click);」とはなりません。
引用返信 編集キー/
■34597 / inTopicNo.24)  Re[16]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (83回)-(2009/04/02(Thu) 11:46:33)
魔界の仮面弁士 さん、丁寧に説明していただきありがとうございます。

>>どちらのLB_Click関数もprivate宣言にしました。
>
> 継承先に LB_Click は不要です。作っても良いですがあまり意味は無いでしょう。

継承元と継承先とでラベルをクリックした際の動作内容が異なるので、
継承先にもラベルをクリックした際のイベントの関数が必要なのです。
#ただ、内容は似たような動作なので、あえて関数名を同じにしています。


> 継承先では、Label.Click イベントを拾って LB_Click にて処理するのではなく、
> 継承元の LBClicked イベントを拾って、Form1_LbClicked にて処理するようにします。
> No34556 でも、そのように書いていますよね。
> >>> また、継承先に用意するのは、Label.Click イベントを受け取るための LB_Click ではなく、
> >>> 継承元フォーム.LbClicked イベントを受け取るための Form1_LbClicked になります。
>
>
>>組み込み終了時点ではコンパイルは通り、継承元のLB_Clickには飛んできました。
>>#継承先のLB_Clickにはまだ飛んできません。
>
> イベント発生時に呼び出されるようにするためには、+= を使って、
> 対象イベントに関連付けねばならない事は御存知かと思います。
>
> しかし、「+=」でセットしたのは、継承元の LB_Click だけであり、
> 継承先の LB_Click はセットしていませんよね。
> ですから、継承先の LB_Click は呼ばれないのです。

試してみようと思い、継承先でも
this.LbClicked += new LbClickedEventHandler(LB_Click);
でイベントのくくりつけを行ってみました。
コンパイルは通りましたが、継承先のLB_Clickへイベントは飛んできませんでした。


>>>>複数のラベルからのイベントを一つに集約した独自イベントを作成
>>のためにくくりつけようとしたのですが、ひょっとして、くくりつけは必要ないのでしょうか?
>
> 括りつけは必要ですが、その相手を間違えています。
>
>
> Label.Click イベントを発生させるのは、Label コントロールです。
> それを LB_Click で受信しようとしているのが、継承元フォームです。
>
> 一方、継承元フォーム.LBClicked イベントを発生させるのは、継承元フォームです。
> それを Form1_LbClicked で受信しようとしているのが、継承先フォームです。
>
>
> つまり、括る相手は、
>  継承元フォーム: ラベル.Click += new EventHandler(LB_Click);
>  継承先フォーム: フォーム.LbClicked += new LbClickedEventHandler(Form1_LBClicked);
> となります。「Lb[i].Click += new LbClickedEventHandler(LB_Click);」とはなりません。

丁寧に説明していただきありがとうございました。
括りつけのやり方がまずかったということですね。
説明していただいた点は理解できましたので、修正を行いました。
ただ、
>  継承先フォーム: フォーム.LbClicked += new LbClickedEventHandler(Form1_LBClicked);
の部分について教えてください。

ここの"フォームとは"継承先のフォームのことだと思うのですが、Form1_LBClickedの"Form1"部分と同じと思って良いのでしょうか?

また、「this.LbClicked +=」まで入力すると自動で
this.LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);
まで入力できるのですが、実際のコードにはEditExtend_LbClickedはありません。
ExitExtendは継承先のフォーム名です。
#自動生成で関数として作成し実行してみましたが、イベントはそこには飛んできませんでした。
this.LbClicked +=new LbClickedEventHandler(this.LB_Click);
に変更してもイベントは飛んできませんでした。
#試しでやってみたのですが、型が違うのにコンパイルが通ったのはなぜでしょう?
せっかく丁寧に解説説明していただいたのに、解決できず、申し訳ありません。
引用返信 編集キー/
■34598 / inTopicNo.25)  Re[17]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1035回)-(2009/04/02(Thu) 13:23:44)
2009/04/02(Thu) 13:27:10 編集(投稿者)

No34597 (tamaboyo さん) に返信
> 継承元と継承先とでラベルをクリックした際の動作内容が異なるので、
> 継承先にもラベルをクリックした際のイベントの関数が必要なのです。

継承先でイベント処理が必要であろう事は理解しているつもりです。
しかし、その処理を記述するべき場所は、継承先の LB_Click ではなく、
継承先の Form1_LbClicked であるという事です。


> #ただ、内容は似たような動作なので、あえて関数名を同じにしています。
先にも書きましたが、その名前は何でも構いません。しかしながら、Click と LBClicked とでは
イベントの引数が異なりますので、そのままでは、今回の独自イベントのハンドラとして登録できません。

強いて言えば、継承先で
 private void Form1_LbClicked(object sender, LbClickedEventArgs e)
 {
  this.LB_Click(e.Label, EventArgs.Empty);
 }
 private void LB_Click(object sender, EventArgs e)
 {
  // ここに必要な処理を記述
 }
のようにして、継承先の LB_Click を呼び出す事はできますが、わざわざ LB_Click を呼びなおさずとも、
最初から Form1_LbClicked に必要な処理を記述すれば済む事なので、
>>> 継承先に LB_Click は不要です。作っても良いですがあまり意味は無いでしょう。
という発言に至ったわけです。


> 試してみようと思い、継承先でも
> this.LbClicked += new LbClickedEventHandler(LB_Click);
> でイベントのくくりつけを行ってみました。
「継承先でも」ではなく、「継承先で」ですよね?

もしかして、継承元でも LbClicked += 〜 を記述しているのでしょうか。
継承元は、独自イベントを発生させる側であって、独自イベントを受け取る側では無いので、
継承元に LbClicked += 〜 は不要です。記述しても良いですが、あまり意味は無いかと。


> コンパイルは通りましたが、継承先のLB_Clickへイベントは飛んできませんでした。
継承元で、LBClicked イベントを発生させていないのではありませんか?

別の表現でいうと、継承元で LB_Click が呼ばれた時に、その中で継承元自身の OnLbClicked メソッドを
呼び出しているかどうかという事です。この部分の具体的なコードは、 No34566 を参照してください。


>  継承先フォーム: フォーム.LbClicked += new LbClickedEventHandler(Form1_LBClicked);
> ここの"フォームとは"継承先のフォームのことだと思うのですが、
そこはどちらでも良いです。base でも this でも好きな方をどうぞ。

何故なら、継承元の「public event LbClickedEventHandler LbClicked;」イベントは、
継承先で再定義されていないからです。
(ゆえに、あえて 継承元/継承先 とは書かず、"フォーム" とのみ表現しています)

もし、イベントを継承先で再定義していた場合は、this.LbClicked と base.LbClicked は
それぞれ異なる意味を持ちます。今回の件が片付いたときにでも追試検証してみてください。


> Form1_LBClickedの"Form1"部分と同じと思って良いのでしょうか?
そのつもりで書きましたが、イベントハンドラのメソッド名は任意なので、さほど気にする必要はありません。
Form1_LbClicked でも MyLabel_Click でも Form2_Labels_Clicked でも tamaboyo_LbClicked でも OK です。

イベントを受け取る側に必要な事は 2 つ。「引数の数と型および戻り値の型が一致している事」と、
「そのメソッドを += 演算子でイベントに割り当てる」と言う 2 点のみであり、
メソッドの名前や引数の名前は、自由に決めて構いません。


今回は、「継承元フォーム」や「継承先フォーム」の名前が分からなかったので、とりあえず Form1 と書きましたが、
実際の継承先のフォーム名は EditExtend なのですね。
> this.LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);
> ExitExtendは継承先のフォーム名です。


ちなみに、「new LbClickedEventHandler」の部分を外して、
 this.LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);

 this.LbClicked += EditExtend_LbClicked;
と記述することも可能です。 No34556 で紹介したコードでは、この記述法で書いています。



> まで入力できるのですが、実際のコードにはEditExtend_LbClickedはありません。
自動生成で十分です。ちなみに、継承元フォームの class 宣言のところに
[DefaultEvent("LbClicked")]
の属性を入れておくと、継承先フォームをダブルクリックした時に自動生成されるメソッドを、
EditExtend_Load から EditExtend_LbClicked へと変更する事ができます。


> #自動生成で関数として作成し実行してみましたが、イベントはそこには飛んできませんでした。
継承元で、イベントを発生させていないからでしょう。


> this.LbClicked +=new LbClickedEventHandler(this.LB_Click);
> に変更してもイベントは飛んできませんでした。
> #試しでやってみたのですが、型が違うのにコンパイルが通ったのはなぜでしょう?
まず、this.LbClicked が要求するのは、LbClickedEventHandler である事はわかりますよね。
ですから、『this.LbClicked +=new LbClickedEventHandler(〜);』は問題ありません。

次に、「new LbClickedEventHandler(this.LB_Click);」の部分ですが、
このとき、LB_Click の引数定義は、(object, EventArgs) になっていますよね。
一方、LbClickedEventHandler の引数定義は、(object, LbClickedEventArgs) です。

型が違うのに受け入れられたのは、LbClickedEventArgs が、EventArgs を
継承したクラスであるからです。


たとえば、Control 型を受け取るメソッドがあって、
 void Foo(Control control)
 {
  MessageBox.Show(control.Name);
 }
これに、TextBox や Label を渡すシーンを思い浮かべてみてください。
  Foo(this.TextBox1);
  Foo(this.Label1);

この場合、「void Foo(TextBox control)」のオーバーロードが無くとも問題ありません。
何故なら、TextBox や Label は、Control クラスを継承しているからです。

それと同じで、イベント発生時に呼び出される (object, LbClickedEventArgs) は、
(object, EventArgs) に渡す事が可能という事です。


上記を踏まえて考えれば、今回の
> this.LbClicked +=new LbClickedEventHandler(this.LB_Click);
が OK であるのに、先の No34575 で書いた
>>> button1.Click += new EventHandler(Form1_FormClosing); // ★NG
>>> button1.Click += new FormClosingEventHandler(Form1_FormClosing); // ★NG
が何故 NG であるのかが分かるかと思いますよ。
引用返信 編集キー/
■34604 / inTopicNo.26)  Re[18]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (84回)-(2009/04/02(Thu) 15:27:56)
魔界の仮面弁士 さん、ありがとうございます。
理解力が低くてお手数をおかけしております。
申し訳ありません。

途中途中で教えていただいた応用については、
希望の動作ができるようになってから確認&勉強させていただきます。



> 先にも書きましたが、その名前は何でも構いません。しかしながら、Click と LBClicked とでは
> イベントの引数が異なりますので、そのままでは、今回の独自イベントのハンドラとして登録できません。
>
> 強いて言えば、継承先で
> のようにして、継承先の LB_Click を呼び出す事はできますが、わざわざ LB_Click を呼びなおさずとも、
> 最初から Form1_LbClicked に必要な処理を記述すれば済む事なので、
> >>> 継承先に LB_Click は不要です。作っても良いですがあまり意味は無いでしょう。
> という発言に至ったわけです。

なるほど。
そういう意味で"意味がない"ということだったのですね。
正しく理解できました。


>>試してみようと思い、継承先でも
>> this.LbClicked += new LbClickedEventHandler(LB_Click);
>>でイベントのくくりつけを行ってみました。
> 「継承先でも」ではなく、「継承先で」ですよね?
>
> もしかして、継承元でも LbClicked += 〜 を記述しているのでしょうか。
> 継承元は、独自イベントを発生させる側であって、独自イベントを受け取る側では無いので、
> 継承元に LbClicked += 〜 は不要です。記述しても良いですが、あまり意味は無いかと。

日本語がおかしいですね、すみません。
継承元にも必要なのかと思ったのですが、Lbにくくりつけしているので不要と思い、記述していません。


>>コンパイルは通りましたが、継承先のLB_Clickへイベントは飛んできませんでした。
> 別の表現でいうと、継承元で LB_Click が呼ばれた時に、その中で継承元自身の OnLbClicked メソッドを
> 呼び出しているかどうかという事です。この部分の具体的なコードは、 No34566 を参照してください。

継承元のLB_Clickで、関数を抜ける直前に
OnLbClicked(new LbClickedEventArgs(label));
の記述を入れています。


> イベントを受け取る側に必要な事は 2 つ。「引数の数と型および戻り値の型が一致している事」と、
> 「そのメソッドを += 演算子でイベントに割り当てる」と言う 2 点のみであり、
> メソッドの名前や引数の名前は、自由に決めて構いません。

教えていただいた通りに修正をして言っているつもりなのですが、まだうまくいっていません。
ちなみに、
> 「そのメソッドを += 演算子でイベントに割り当てる」と言う 2 点のみであり、
のコードですが、
継承元ではArrange関数の中でLbのインスタンス作成を行っているfor文中、
継承先では、継承元のArrange関数から戻ってきた後に記述していますが、
このタイミングが悪くて括りつけが行われない、ということはないですよね?


>>#自動生成で関数として作成し実行してみましたが、イベントはそこには飛んできませんでした。
> 継承元で、イベントを発生させていないからでしょう。

ちょっと整理させてください。
ここでいうイベントとは、LB_Clickに飛ん出来ていない、ということでしょうか?
それとも、宣言した
public class LbClickedEventArgs : EventArgs
{
private Label label;
public Label Labels { get { return label; } }
public LbClickedEventArgs(Label label) { this.label = label; }
}
に飛んできていないということでしょうか?
現在は、継承元のLbをクリックすると宣言にも飛んできますが、
継承先のLbをクリックしてもこの宣言には飛んできていません。
引用返信 編集キー/
■34606 / inTopicNo.27)  Re[19]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1037回)-(2009/04/02(Thu) 16:19:27)
No34604 (tamaboyo さん) に返信
> 理解力が低くてお手数をおかけしております。
いえ、こちらの説明が不足している部分もあるかと思うので、
不明な点はその都度、再質問していただいた方がありがたいです。

# こうしたやり取りは、教える側にとっても勉強になります。


>>>コンパイルは通りましたが、継承先のLB_Clickへイベントは飛んできませんでした。
>> 別の表現でいうと、継承元で LB_Click が呼ばれた時に、その中で継承元自身の OnLbClicked メソッドを
>> 呼び出しているかどうかという事です。この部分の具体的なコードは、 No34566 を参照してください。
> 継承元のLB_Clickで、関数を抜ける直前に
> OnLbClicked(new LbClickedEventArgs(label));
> の記述を入れています。

以下の点を確認してみてください。

(1) 継承元の LB_Click 内にある、「OnLbClicked(new LbClickedEventArgs(label));」の行が実行されているか。
 → OnEventName メソッドは、イベントを発生させる為に用意されるメソッドです。

(2) 継承元の OnLbClicked の中にある、「LbClicked(this, e);」の行が実行されているか。
 → これが最も重要な箇所です。これにより、LbClicked イベントが発生します。

(3) 継承先で「LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);」が実行されているか。
 → ここでイベントハンドラとして登録されたメソッドが、イベント発生時に呼び出される事になります。

(4) 継承先で LbClicked のイベントやその他のメソッドを再定義していたりはしないか。
 → 継承先で処理を上書きしてしまうと、継承元からの通知を握りつぶしてしまう結果になりかねません。


> 継承元ではArrange関数の中でLbのインスタンス作成を行っているfor文中、
『Lb[i].Click += new EventHandler(this.LB_Click);』を実行するとすれば、
タイミングとしてはそこでしょうね。


> 継承先では、継承元のArrange関数から戻ってきた後に記述していますが、
いつでも良いとは思いますが、私はフォームのロード時に割り当てています。

 void EditExtend_Load(objcet sender, EventArgs e)
 {
  this.LbClicked += EditExtend_LbClicked;
 }


> このタイミングが悪くて括りつけが行われない、ということはないですよね?
+= で登録する前に発生したイベントは当然拾えませんが、
+= で登録した後に発生したイベントであれば拾えるはずです。


>>>#自動生成で関数として作成し実行してみましたが、イベントはそこには飛んできませんでした。
>>継承元で、イベントを発生させていないからでしょう。
> ちょっと整理させてください。
> ここでいうイベントとは、LB_Clickに飛ん出来ていない、ということでしょうか?
LB_Click が呼ばれた際に、LBClicked イベントを発生させているか否か、という事です。


> それとも、宣言した
> public class LbClickedEventArgs : EventArgs
> {
> private Label label;
> public Label Labels { get { return label; } }
> public LbClickedEventArgs(Label label) { this.label = label; }
> }
> に飛んできていないということでしょうか?

それはイベントではありません。

イベントの宣言は、
>>> public event LbClickedEventHandler LbClicked;
の部分です。そして、ここで宣言したイベントを発生させているのが、
>>> LbClicked(this, e);
の行です。

継承元で LbClicked(this, e); を呼びだすことで、
継承先の「LbClicked += 〜」で割り当てられたメソッドも呼び出されます。
引用返信 編集キー/
■34608 / inTopicNo.28)  Re[20]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (85回)-(2009/04/02(Thu) 17:41:37)
魔界の仮面弁士 さん、ありがとうございます。

>>理解力が低くてお手数をおかけしております。
> いえ、こちらの説明が不足している部分もあるかと思うので、
> 不明な点はその都度、再質問していただいた方がありがたいです。
>
> # こうしたやり取りは、教える側にとっても勉強になります。

そう言っていただけるとありがたいです。
もう少しで解決しそうな気がしているのですが、、、よろしくお願いします。


> >>>コンパイルは通りましたが、継承先のLB_Clickへイベントは飛んできませんでした。
> >> 別の表現でいうと、継承元で LB_Click が呼ばれた時に、その中で継承元自身の OnLbClicked メソッドを
> >> 呼び出しているかどうかという事です。この部分の具体的なコードは、 No34566 を参照してください。
>>継承元のLB_Clickで、関数を抜ける直前に
>>OnLbClicked(new LbClickedEventArgs(label));
>>の記述を入れています。
>
> 以下の点を確認してみてください。
>
> (1) 継承元の LB_Click 内にある、「OnLbClicked(new LbClickedEventArgs(label));」の行が実行されているか。
>  → OnEventName メソッドは、イベントを発生させる為に用意されるメソッドです。

この行にブレイクをかけているのですが
継承元のフォームを表示させてラベルをクリックすると、ブレイクが引っ掛かります。
継承先のフォームを表示させてラベルをクリックしても、ブレイクは引っ掛かりません。


> (2) 継承元の OnLbClicked の中にある、「LbClicked(this, e);」の行が実行されているか。
>  → これが最も重要な箇所です。これにより、LbClicked イベントが発生します。
>
ブレイクをかけて継承元のフォームを表示させてラベルをクリックさせてみましたが、
このブレイクには引っ掛かりませんでした。
その前の、if (LbClicked != null)の条件文で抜けています。

もちろん、継承先のフォームを表示させてラベルをクリックしても引っ掛かりません。


> (3) 継承先で「LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);」が実行されているか。
>  → ここでイベントハンドラとして登録されたメソッドが、イベント発生時に呼び出される事になります。

ブレイクをかけているのですがフォームを表示するタイミングで引っ掛かります。


> (4) 継承先で LbClicked のイベントやその他のメソッドを再定義していたりはしないか。
>  → 継承先で処理を上書きしてしまうと、継承元からの通知を握りつぶしてしまう結果になりかねません。

今は LbClickedの再定義はコメントにしています。
#はじめは継承元をvirtualにしていたので、overrideで定義していました。
継承先のEditExtend_LbClickedを抜ける直前にも
OnLbClicked(new LbClickedEventArgs(label));
の記述をしていますが、それで再定義になりますでしょうか?
その他、思いつく再定義はないつもりです。
#検索かけましたが引っ掛かりませんでした。

(2)で引っ掛かってないので、それが原因ということでしょうか。
LB_Click関数のOnLbClicked(new LbClickedEventArgs(label));で
引数で渡しているlabelは、
Label label = (Label)sender;
で定義&値の設定をしています。
この時点ではnullではないのですが、OnBitClickedの飛んできたときにはnullになっています。


>>継承元ではArrange関数の中でLbのインスタンス作成を行っているfor文中、
> 『Lb[i].Click += new EventHandler(this.LB_Click);』を実行するとすれば、
> タイミングとしてはそこでしょうね。

はい、そこでその通りに設定しています。


>>継承先では、継承元のArrange関数から戻ってきた後に記述していますが、
> いつでも良いとは思いますが、私はフォームのロード時に割り当てています。

フォームを呼び出す側のフォームから呼ばれるラベルの個数を渡される関数の中で設定していますが、
この関数を抜けたあとでShowDialogしているので、大丈夫だと思います。


>>このタイミングが悪くて括りつけが行われない、ということはないですよね?
> += で登録する前に発生したイベントは当然拾えませんが、
> += で登録した後に発生したイベントであれば拾えるはずです。

フォームが表示されるまでに、継承元、継承先とも括りつけは終了しています。


> >>>#自動生成で関数として作成し実行してみましたが、イベントはそこには飛んできませんでした。
> >>継承元で、イベントを発生させていないからでしょう。
>>ちょっと整理させてください。
>>ここでいうイベントとは、LB_Clickに飛んで来ていない、ということでしょうか?
> LB_Click が呼ばれた際に、LBClicked イベントを発生させているか否か、という事です。
>
> イベントの宣言は、
> >>> public event LbClickedEventHandler LbClicked;
> の部分です。そして、ここで宣言したイベントを発生させているのが、
> >>> LbClicked(this, e);
> の行です。
>
> 継承元で LbClicked(this, e); を呼びだすことで、
> 継承先の「LbClicked += 〜」で割り当てられたメソッドも呼び出されます。

継承元でイベントが発生できていないということだったのですね。
イベントの宣言は
public event LbClickedEventHandler LbClicked;
protected void OnLbClicked(LbClickedEventArgs e)
{
if (LbClicked != null)
{
LbClicked(this, e);
}
}
です。
あっていると思うのですが・・・?
引用返信 編集キー/
■34609 / inTopicNo.29)  Re[21]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1038回)-(2009/04/02(Thu) 20:27:45)
No34608 (tamaboyo さん) に返信
>>(1) 継承元の LB_Click 内にある、「OnLbClicked(new LbClickedEventArgs(label));」の行が実行されているか。
>> → OnEventName メソッドは、イベントを発生させる為に用意されるメソッドです。
> この行にブレイクをかけているのですが
> 継承元のフォームを表示させてラベルをクリックすると、ブレイクが引っ掛かります。
> 継承先のフォームを表示させてラベルをクリックしても、ブレイクは引っ掛かりません。

まずは、ここに問題がありそうなのですが、その原因が思い当たりません。
(当方では、EditExtend からクリックしても一時停止されるのですけれども)

継承先で OnLbClicked をオーバーライドして、base.OnLbClicked(e); を握りつぶしてしまえば
そのようになりますが、今回は virtual にしていないようですし…。


>>(2) 継承元の OnLbClicked の中にある、「LbClicked(this, e);」の行が実行されているか。
>> → これが最も重要な箇所です。これにより、LbClicked イベントが発生します。
> ブレイクをかけて継承元のフォームを表示させてラベルをクリックさせてみましたが、
> このブレイクには引っ掛かりませんでした。
> その前の、if (LbClicked != null)の条件文で抜けています。

null という事は、その時点で「.LbClicked += 〜」での登録作業が
どこからも行われていないという事になりますね。

今回、何故か継承先から OnLbClicked が呼ばれていないようなので、
このコードが実行されているのは、継承先フォームから呼ばれた時ではなく、
> 継承元のフォームを表示させてラベルをクリックすると、
の場合なのでしょう。

継承元では「.LbClicked += 〜」を登録しませんから、今回はここが
null になってしまったのでは無いかと。


> もちろん、継承先のフォームを表示させてラベルをクリックしても引っ掛かりません。
(1) を通らないのですから、そうなりますね。


>>(3) 継承先で「LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);」が実行されているか。
>> → ここでイベントハンドラとして登録されたメソッドが、イベント発生時に呼び出される事になります。
> ブレイクをかけているのですがフォームを表示するタイミングで引っ掛かります。
その登録箇所を通過しているという事ですね?


> 継承先のEditExtend_LbClickedを抜ける直前にも
> OnLbClicked(new LbClickedEventArgs(label));
> の記述をしていますが、それで再定義になりますでしょうか?

再定義にはなりませんが、そのコードには問題があると思います。
OnLbClicked はイベントを強制発生させるためのメソッドですから、
それだと、イベントが連鎖してしまうと思いますよ。

EditExtend_LbClicked で base.OnLbClicked を呼び出すという事は、
いわば、下記のような処理を実行しているのと同じ結果をもたらします。

 private void button1_Click(object sender, EventArgs e)
 {
  Text = DateTime.Now.ToString("HH:mm:ss.ffff");

  button1.PerformClick(); // Click イベントを発生させる。
 }


> (2)で引っ掛かってないので、それが原因ということでしょうか。
(2) が発生しないなら、LbClicked イベントは絶対に機能しません。
ただ、その原因は (1) が継承先から呼ばれないことにあるような気もします。


> LB_Click関数のOnLbClicked(new LbClickedEventArgs(label));で
> 引数で渡しているlabelは、
> Label label = (Label)sender;
> で定義&値の設定をしています。
> この時点ではnullではないのですが、OnBitClickedの飛んできたときにはnullになっています。

??
今回のスレッドのなかで、OnBitClicked というメソッド名は初めて目にしますが、
それは何者でしょうか。名前からして、BitClicked イベントの発火用メソッドだと
思いますが、それと OnLbClicked との関係が分かりません。


> 継承元でイベントが発生できていないということだったのですね。
> イベントの宣言は
> (snip)
> です。
> あっていると思うのですが・・・?
この部分は問題無さそうですね。

…とすると、何が原因なのでしょうね。

もしかしたら、別の箇所に問題があるのかも知れませんが( No34513 のように)、
今のところ、原因が思い当たらないです。
>>> 投稿してから、いらない部分を消し、コードを整理したところ、イベントが取れるようになりました。


比較用に、当方での手書き実装例を置いておきます。
(解決前なので、実際に見るかどうかの判断はお任せしますが)

Arrange関数を実装する前の、void Contorol_Load(int nMax) によるコード( No34500 )です。
http://www.vb-user.net/junk/replySamples/2009.04.22.18.45/34467.ZIP
引用返信 編集キー/
■34624 / inTopicNo.30)  Re[22]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (86回)-(2009/04/03(Fri) 09:42:27)
魔界の仮面弁士 さん、ありがとうございます。

> >>(1) 継承元の LB_Click 内にある、「OnLbClicked(new LbClickedEventArgs(label));」の行が実行されているか。
> >> → OnEventName メソッドは、イベントを発生させる為に用意されるメソッドです。
>>この行にブレイクをかけているのですが
>>継承元のフォームを表示させてラベルをクリックすると、ブレイクが引っ掛かります。
>>継承先のフォームを表示させてラベルをクリックしても、ブレイクは引っ掛かりません。
>
> まずは、ここに問題がありそうなのですが、その原因が思い当たりません。
> (当方では、EditExtend からクリックしても一時停止されるのですけれども)
>
> 継承先で OnLbClicked をオーバーライドして、base.OnLbClicked(e); を握りつぶしてしまえば
> そのようになりますが、今回は virtual にしていないようですし…。

はい、今はvirtualにはしていません。
コードが正しければ、継承先のフォームでラベルをクリックすると、
継承元のブレイクで引っかかるのですね。
ということは、動作の流れは、継承元のLB_Clickを抜けた後で
継承先のクリックイベントに飛んでくるということになるのでしょうか。


> >>(2) 継承元の OnLbClicked の中にある、「LbClicked(this, e);」の行が実行されているか。
> >> → これが最も重要な箇所です。これにより、LbClicked イベントが発生します。
>>ブレイクをかけて継承元のフォームを表示させてラベルをクリックさせてみましたが、
>>このブレイクには引っ掛かりませんでした。
>>その前の、if (LbClicked != null)の条件文で抜けています。
>
> null という事は、その時点で「.LbClicked += 〜」での登録作業が
> どこからも行われていないという事になりますね。
>
> 今回、何故か継承先から OnLbClicked が呼ばれていないようなので、
> このコードが実行されているのは、継承先フォームから呼ばれた時ではなく、
>>継承元のフォームを表示させてラベルをクリックすると、
> の場合なのでしょう。
>
> 継承元では「.LbClicked += 〜」を登録しませんから、今回はここが
> null になってしまったのでは無いかと。

動作の流れとしては、継承元で
Lb[i].Click += new EventHandler(this.LB_Click);
でクリックイベントを括りつけしているので、、LB_Click関数の中で、抜ける直前に
OnLbClicked(new LbClickedEventArgs(label));
しています。
これだけでは足りないということでしょうか?
#でも通っているので、足りているということだとも思うのですが。


> >>(3) 継承先で「LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);」が実行されているか。
> >> → ここでイベントハンドラとして登録されたメソッドが、イベント発生時に呼び出される事になります。
>>ブレイクをかけているのですがフォームを表示するタイミングで引っ掛かります。
> その登録箇所を通過しているという事ですね?

はい。通っています。


>>継承先のEditExtend_LbClickedを抜ける直前にも
>>OnLbClicked(new LbClickedEventArgs(label));
>>の記述をしていますが、それで再定義になりますでしょうか?
> 継承先の
> 再定義にはなりませんが、そのコードには問題があると思います。
> OnLbClicked はイベントを強制発生させるためのメソッドですから、
> それだと、イベントが連鎖してしまうと思いますよ。

なるほど。
今はEditExtend_LbClickedに飛んできていないので、まだ問題は発生していなかったということですね。


>>(2)で引っ掛かってないので、それが原因ということでしょうか。
> (2) が発生しないなら、LbClicked イベントは絶対に機能しません。
> ただ、その原因は (1) が継承先から呼ばれないことにあるような気もします。
>
>>LB_Click関数のOnLbClicked(new LbClickedEventArgs(label));で
>>引数で渡しているlabelは、
>> Label label = (Label)sender;
>>で定義&値の設定をしています。
>>この時点ではnullではないのですが、OnBitClickedの飛んできたときにはnullになっています。
>
> ??
> 今回のスレッドのなかで、OnBitClicked というメソッド名は初めて目にしますが、
> それは何者でしょうか。名前からして、BitClicked イベントの発火用メソッドだと
> 思いますが、それと OnLbClicked との関係が分かりません。

すみません、OnBitClickedの部分は、OnLbClickedの間違いです。

今、LB_Click関数を抜けた後
public delegate void LbClickedEventHandler(object sender, LbClickedEventArgs e);
public class LbClickedEventArgs : EventArgs
{
private Label label;
public Label Labels { get { return label; } }
public LbClickedEventArgs(Label label) { this.label = label; } //☆
}
を通るので、☆の部分にブレイクをかけているのですが、
LbClickedEventArgs(Label label)の引数で渡されるlabelには値が入っているので、そのあとのthis.labelに値は設定されます。
これが、そのあともう一度LB_Click関数のOnLbClicked(new LbClickedEventArgs(label))を通ってから
OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
OnLbClickedに飛んできたときにnullになっています。
なぜ、値を渡しているのになぜnullになるのでしょうか?


> もしかしたら、別の箇所に問題があるのかも知れませんが( No34513 のように)、
> 今のところ、原因が思い当たらないです。
> >>> 投稿してから、いらない部分を消し、コードを整理したところ、イベントが取れるようになりました。

可能性は捨てきれないのですが、、、
同じようにボタンのクリックイベントをvirtualとoverrideで宣言しているところがあるのですが、
そこが影響を及ぼすということはありえるのでしょうか?
#ラベルが解決したら、そこも同じ様に修正をかけようと現在放置しています。
#ひょっとしたら、そこはvirtualする必要はないかも?と思って、放置中でもあります。


> 比較用に、当方での手書き実装例を置いておきます。
> (解決前なので、実際に見るかどうかの判断はお任せしますが)

あと少しで解決しそうな気がするので、もう少しお預けにします。
頑張ります。
引用返信 編集キー/
■34625 / inTopicNo.31)  Re[23]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1039回)-(2009/04/03(Fri) 11:02:39)
No34624 (tamaboyo さん) に返信
> ということは、動作の流れは、継承元のLB_Clickを抜けた後で
> 継承先のクリックイベントに飛んでくるということになるのでしょうか。

期待される処理の流れは、以下のようになります。

イベント Label.Click 発火
 → 継承元 LB_Click が呼ばれる → 継承元 OnLbClicked を呼び出す
  → 継承元 OnLbClicked が呼ばれる → イベント LbClicked 発火
   → 継承先 EditExtend_LbClicked が呼ばれる


> 動作の流れとしては、継承元で
> Lb[i].Click += new EventHandler(this.LB_Click);
> でクリックイベントを括りつけしているので、、LB_Click関数の中で、抜ける直前に
> OnLbClicked(new LbClickedEventArgs(label));
> しています。
> これだけでは足りないということでしょうか?
話を聞く限り、継承元の実装は問題無いように思えます。
(となると、疑うべきは継承先の方?)



> 今、LB_Click関数を抜けた後
> public delegate void LbClickedEventHandler(object sender, LbClickedEventArgs e);
> public class LbClickedEventArgs : EventArgs
> {
> private Label label;
> public Label Labels { get { return label; } }
> public LbClickedEventArgs(Label label) { this.label = label; } //☆
> }
> を通るので、☆の部分にブレイクをかけているのですが、
> LbClickedEventArgs(Label label)の引数で渡されるlabelには値が入っているので、そのあとのthis.labelに値は設定されます。
> これが、そのあともう一度LB_Click関数のOnLbClicked(new LbClickedEventArgs(label))を通ってから
> OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
> OnLbClickedに飛んできたときにnullになっています。
> なぜ、値を渡しているのになぜnullになるのでしょうか?

同名の "label" があちこちにあるので、整理しながら見ていきます。

> LbClickedEventArgs(Label label)の引数で渡されるlabelには値が入っているので
この label は、「LbClickedEventArgs のコンストラクタ引数」の事ですね。

> そのあとのthis.labelに値は設定されます。
この label は、「LbClickedEventArgs のフィールド変数」だと思います。

> これが、そのあともう一度LB_Click関数のOnLbClicked(new LbClickedEventArgs(label))を通ってから
これは「もう一度通っている」というよりも、
『new LbClickedEventArgs(label)』の部分と『OnLbClicked(〜);』の部分とが、
それぞれステップ実行されているという事でしょうね。

デバッグ時の流れを追いやすくするため、
 OnLbClicked(new LbClickedEventArgs(label));
の部分を、
 LbClickedEventArgs arg = new LbClickedEventArgs(label);
 OnLbClicked(arg);
の 2 行に分けておく事をお薦めします。


> OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
> OnLbClickedに飛んできたときにnullになっています。
この label が、どれを指しているのか読み取れなかったのですが、デバッグ時に、
上記でいうところの、インスタンス「arg」の有効範囲を読み違えている可能性はありませんか?



>>もしかしたら、別の箇所に問題があるのかも知れませんが( No34513 のように)、
>>今のところ、原因が思い当たらないです。
>可能性は捨てきれないのですが、、、
いきなり今のコードに組み込もうとするのでは無く、まずは今回の範囲について、
単純な実験コードを作って、動作検証を行うようにしてみてください。

個々のパーツが完全で無いうちに、全体の組み上げに取り掛かってしまうと、
問題発生時の切り分けが難しくなってしまいますから。


> 同じようにボタンのクリックイベントをvirtualとoverrideで宣言しているところがあるのですが、
> そこが影響を及ぼすということはありえるのでしょうか?

イベントのオーバーライドという事は、こういう意味でしょうか?

// 継承元
public virtual event EventHandler MyEvent;

// 継承先
public override event EventHandler MyEvent;


だとすると、継承元で「MyEvent(this, EventArgs.Empty);」が実行されても、
継承先の「void foo_MyEvent(object sender, EventArgs e)」メソッドは呼び出されません。

この場合、継承先の「void foo_MyEvent(object sender, EventArgs e)」が呼び出れるのは、
継承先で「MyEvent(this, EventArgs.Empty);」が実行された場合のみです。

もし、イベントが継承先でオーバーライドされていないのであれば、
継承元で「MyEvent(this, EventArgs.Empty);」が実行されたタイミングで、
継承先の「void foo_MyEvent(object sender, EventArgs e)」が呼び出されます。
引用返信 編集キー/
■34629 / inTopicNo.32)  Re[24]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (87回)-(2009/04/03(Fri) 12:04:28)
魔界の仮面弁士 さん、ありがとございます。

>>ということは、動作の流れは、継承元のLB_Clickを抜けた後で
>>継承先のクリックイベントに飛んでくるということになるのでしょうか。
>
> 期待される処理の流れは、以下のようになります。
>
> イベント Label.Click 発火
>  → 継承元 LB_Click が呼ばれる → 継承元 OnLbClicked を呼び出す
>   → 継承元 OnLbClicked が呼ばれる → イベント LbClicked 発火
>    → 継承先 EditExtend_LbClicked が呼ばれる

なるほど。
継承元のLB_Clickは継承先からも呼ばれてしまうのですね。

でも、今はまだ継承元のLB_Clickも呼ばれていません。


> 話を聞く限り、継承元の実装は問題無いように思えます。
> (となると、疑うべきは継承先の方?)

継承先で行っているのは、
フォーム表示前にイベントの括りつけ
this.LbClicked += new LbClickedEventHandler(EditExtend_LbClicked);
だけのはずなのですが・・・


>>今、LB_Click関数を抜けた後
>> public delegate void LbClickedEventHandler(object sender, LbClickedEventArgs e);
>> public class LbClickedEventArgs : EventArgs
>> {
>> private Label label;
>> public Label Labels { get { return label; } }
>> public LbClickedEventArgs(Label label) { this.label = label; } //☆
>> }
>>を通るので、☆の部分にブレイクをかけているのですが、
>>LbClickedEventArgs(Label label)の引数で渡されるlabelには値が入っているので、そのあとのthis.labelに値は設定されます。
>>これが、そのあともう一度LB_Click関数のOnLbClicked(new LbClickedEventArgs(label))を通ってから
>>OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
>>OnLbClickedに飛んできたときにnullになっています。
>>なぜ、値を渡しているのになぜnullになるのでしょうか?
>
> 同名の "label" があちこちにあるので、整理しながら見ていきます。
>
>>LbClickedEventArgs(Label label)の引数で渡されるlabelには値が入っているので
> この label は、「LbClickedEventArgs のコンストラクタ引数」の事ですね。

はいそうです。


>>そのあとのthis.labelに値は設定されます。
> この label は、「LbClickedEventArgs のフィールド変数」だと思います。

ここのlabelは☆の行の{}の中をさしています。


> デバッグ時の流れを追いやすくするため、
>  OnLbClicked(new LbClickedEventArgs(label));
> の部分を、
>  LbClickedEventArgs arg = new LbClickedEventArgs(label);
>  OnLbClicked(arg);
> の 2 行に分けておく事をお薦めします。
>
>>OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
>>OnLbClickedに飛んできたときにnullになっています。
> この label が、どれを指しているのか読み取れなかったのですが、デバッグ時に、
> 上記でいうところの、インスタンス「arg」の有効範囲を読み違えている可能性はありませんか?

ここで言っていたlabelは、
LbClickedEventArgs arg = new LbClickedEventArgs(label);
のLbClickedEventArgs(label)の()の中のlabelです。

LbClickedEventArgs arg = new LbClickedEventArgs(label);
を2行に分けて実行してみたところ、OnLbClicked(arg)のargには値が入った状態でOnLbClickedに飛んでいます。

> 上記でいうところの、インスタンス「arg」の有効範囲を読み違えている可能性はありませんか?
の意味が分からなかったのですが、argと
protected void OnLbClicked(LbClickedEventArgs e)
の引数の「e」とは違うものなのでしょうか?


> いきなり今のコードに組み込もうとするのでは無く、まずは今回の範囲について、
> 単純な実験コードを作って、動作検証を行うようにしてみてください。
>
> 個々のパーツが完全で無いうちに、全体の組み上げに取り掛かってしまうと、
> 問題発生時の切り分けが難しくなってしまいますから。

すみません。
元々のソースをそのまま修正かけています。
切り離してやっているときに必要なところまでコメントをかけてしまい、
最初の凡ミスが発生してしまったので・・・


>>同じようにボタンのクリックイベントをvirtualとoverrideで宣言しているところがあるのですが、
>>そこが影響を及ぼすということはありえるのでしょうか?
>
> イベントのオーバーライドという事は、こういう意味でしょうか?
>
> // 継承元
> public virtual event EventHandler MyEvent;
>
> // 継承先
> public override event EventHandler MyEvent;

ほぼそういう意味です。
[継承元]
public event EventHandler ALLClick;
protected virtual void OnALLClicked(object sender, EventArgs e)
{
if (ALLClick != null)
{
ALLClick(this, e);
}
}
[継承先]
public new event EventHandler ALLClick;
protected override void OnALLClicked(object sender, EventArgs e)
{
if (ALLClick != null)
{
ALLClick(this, e);
}
}
ラベルについて説明頂いている中でこのボタンについてnewする必要はないのかも、とは思ったのですが、
#両方をprivateにすればいいだけでは?と思っていますし、そもそも宣言が必要なのか考えなおすべきだと思うので。
とりあえずラベルのクリックには影響ないと思ってそのまま放置しています。
ラベルクリックの動作をきちんとしてからにしようと思っていますので。
引用返信 編集キー/
■34639 / inTopicNo.33)  Re[25]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1040回)-(2009/04/04(Sat) 06:15:17)
2009/04/06(Mon) 01:44:04 編集(投稿者)

No34629 (tamaboyo さん) に返信
> でも、今はまだ継承元のLB_Clickも呼ばれていません。
こちらで試した時は呼ばれていたのですが、何が違うのでしょうね…。

継承先フォームの方を表示している時にも、
継承元にある「Lb[i].Click += LB_Click;」の処理が
行われているかどうかを確認してみてください。


>>> public LbClickedEventArgs(Label label) { this.label = label; } //☆
>>> そのあとのthis.labelに値は設定されます。
>>この label は、「LbClickedEventArgs のフィールド変数」だと思います。
> ここのlabelは☆の行の{}の中をさしています。
☆の行の、{ this.label = label; } の左側の方を指しているのですね?

だとすればそれは、「private Label label;」を指す物なので、
フィールド変数という事になるかと。


>> LbClickedEventArgs arg = new LbClickedEventArgs(label);
>> OnLbClicked(arg);
>>の 2 行に分けておく事をお薦めします。
> LbClickedEventArgs arg = new LbClickedEventArgs(label);
> を2行に分けて実行してみたところ、OnLbClicked(arg)のargには値が入った状態でOnLbClickedに飛んでいます。
値が入った状態というのは、arg != null かつ、arg.Label != null という事でしょうか?


>>上記でいうところの、インスタンス「arg」の有効範囲を読み違えている可能性はありませんか?
> の意味が分からなかったのですが、argと
> protected void OnLbClicked(LbClickedEventArgs e)
> の引数の「e」とは違うものなのでしょうか?
同じ物のはずです。それゆえ、呼び出し前と呼び出し中で結果が変わるという状況を想像できなかったので、
もしかしたら、デバッグ方法に問題があったのかな、と勘繰りました。


>>>OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
>>>OnLbClickedに飛んできたときにnullになっています。
再度確認させていただきたいのですが、それは OnLbClicked が呼び出された時点で、
e == null になってしまっているという事なのでしょうか。
それとも、e != null ではあるけれども、e.Label == null であっていたという事なのでしょうか。


> 切り離してやっているときに必要なところまでコメントをかけてしまい、
> 最初の凡ミスが発生してしまったので・・・
その「必要なところ」とそうでないところの切り分けのためにも、
実験用の小さな別プロジェクトを作成することをおすすめします。


>>イベントのオーバーライドという事は、こういう意味でしょうか?
> ほぼそういう意味です。
new/override の違いを理解された上で書かれているのか不安ですが、
とりあえず、ラベルのクリックの件とは無関係なので、今は触れないでおきます。

ただし、継承目的のクラスを作るのであれば、private/protected/public などの
スコープや、virtual/abstract および override/new の使い分けは、
設計段階できちんと決めておいた方が良いかと思います。継承フォームの場合は特に。

# 同名メソッドを作ったら競合したので、とりあえず new/override をつけたら
# コンパイルが通った…などという行き当たりばったりな実装は NG です。


> ラベルについて説明頂いている中でこのボタンについてnewする必要はないのかも、とは思ったのですが、
> #両方をprivateにすればいいだけでは?と思っていますし、
『イベントを受け取るためのメソッド』は、通常は「private」で宣言する事になるでしょう。
実際、Visual Studio が自動生成する void button1_Click は、 private として自動生成されますよね。

何故なら、button1_Click はイベントによって呼び出されるべきものであって、ほとんどの場合、
外部から button1_Click(button1, EventArgs.Empty); として呼び出す必要は無いからです。

なお、Control.OnClick メソッドなどの『イベントを発生させるためのメソッド』の方は、、
それが他のクラスに継承させることを目的としたクラスである場合、その宣言は
protected virtual なメソッドとして宣言するのが一般的のようです。
http://msdn.microsoft.com/ja-jp/library/wkzf914z.aspx

ただし、それが sealed class (Microsoft.Win32.SystemEvents クラスなど)であった場合、
イベントを発生させるためのメソッドは、private またはそもそも実装しない事が多いかと。

# ただし、ToolStripSplitButton.PerformButtonClick メソッドや
# Button.PerformClick メソッドのように、意図的に public として
# 実装されるケースもあります。
引用返信 編集キー/
■34702 / inTopicNo.34)  Re[26]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (88回)-(2009/04/06(Mon) 17:08:19)
魔界の仮面弁士 さん、ありがとうございます。
投稿が遅くなりました。

> 継承先フォームの方を表示している時にも、
> 継承元にある「Lb[i].Click += LB_Click;」の処理が
> 行われているかどうかを確認してみてください。

ブレイクをかけて実行すると、引っ掛かります。
このコードを通った後に、継承先の
LbClicked += EditExtend_LbClicked;
を通ります。
#順番はあってますよね?


> >> LbClickedEventArgs arg = new LbClickedEventArgs(label);
> >> OnLbClicked(arg);
> >>の 2 行に分けておく事をお薦めします。
>>LbClickedEventArgs arg = new LbClickedEventArgs(label);
>>を2行に分けて実行してみたところ、OnLbClicked(arg)のargには値が入った状態でOnLbClickedに飛んでいます。
> 値が入った状態というのは、arg != null かつ、arg.Label != null という事でしょうか?

OnLbClicked(arg)
でブレイクが引っ掛かってる状態でウォッチリストを見ると、
arg {LbClickedEventArgs}
label {Label, Text: 0}
の値が入っています。
#プロジェクト名は長いので削除しています。
nullではないと思うのですが。


> >>上記でいうところの、インスタンス「arg」の有効範囲を読み違えている可能性はありませんか?
>>の意味が分からなかったのですが、argと
>>protected void OnLbClicked(LbClickedEventArgs e)
>>の引数の「e」とは違うものなのでしょうか?
> 同じ物のはずです。それゆえ、呼び出し前と呼び出し中で結果が変わるという状況を想像できなかったので、
> もしかしたら、デバッグ方法に問題があったのかな、と勘繰りました。

その近辺にブレイクをかけて[F10]でステップ実行しています。


> >>>OnLbClickedに飛ぶのですが、LB_Click関数を抜けるときにはlabelに値が設定されているのに、
> >>>OnLbClickedに飛んできたときにnullになっています。
> 再度確認させていただきたいのですが、それは OnLbClicked が呼び出された時点で、
> e == null になってしまっているという事なのでしょうか。
> それとも、e != null ではあるけれども、e.Label == null であっていたという事なのでしょうか。

[F10]で実行して、OnLbClickedに飛んできた際の値は
e {LbClickedEventArgs}
label {Label, Text: 0}
です。
eの値はnullではないのですが、
if (LbClicked != null)
のLbClickedの値がnullのため、
LbClicked(this, e);
は実行されません。
この説明でわかっていただけますでしょうか?



週末、ちょっと気になったので、お試しでやってみたことがあります。
元々はラベルコントロールをパネルコントロールに追加するところから始まりました。
以前、追加していなかった場合は、継承先でイベントが取れていたので、動作はどうだったのかな?と思い、
ラベルコントロールを
this.Controls.AddRange(this.Lb);
でフォームに追加の形にしました。(以前のコードに戻しました)
これで、動作を確認したところ、
継承元の動作、値はラベルをパネルにAddRangeしてもしなくても値は上記結果と同じでした。
ただ、継承先のフォームからラベルをクリックすると、
継承元のLB_ClickからOnLbClickedに飛んだ際に、
LbClicked(this, e);
のコードを通りました。
そのため、そのあとに継承先にあるEditExtend_BitClickedも通りました。
#EditExtend_BitClickedのLabel label = (Label)sender;でエラーになりましたが。
ラベルをパネルに追加しなかった場合、継承先の動作は希望のものになるようです。

とりあえず、継承元の動作は元からおかしかったということが分かったのですが、
パネルにAddRangeするかしないかでLB_Clickを通ったり通らなかったりと、
継承先の動作が変わってしまうのはなぜなのでしょうか?


> >>イベントのオーバーライドという事は、こういう意味でしょうか?
>>ほぼそういう意味です。
> new/override の違いを理解された上で書かれているのか不安ですが、
> とりあえず、ラベルのクリックの件とは無関係なので、今は触れないでおきます。

はい、ラベルが解決したら再度見直し&考えなおしの予定です。
引用返信 編集キー/

<前の20件
トピック内ページ移動 / << 0 | 1 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -