質問者
イベントハンドラについて

質問
-
以前から漠然と疑問に思っていることがあります。
フォームのイベントハンドラなどで例えば
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
は MyBase.Load というふうに基底クラスのイベントをハンドルしますが、
Private Sub Form1_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Enter
End Sub
は Me.Enter というふうに自クラスのイベントをハンドルします。
Form1内でイベントをオーバーライドしているわけでもないのにこの違いがよく理解できません。
敢えて異なることに何か意味があるのでしょうか?
すべての返信
-
まどか さんからの引用
・デザイナでフォームをダブルクリック → MyBase.Load
・コードエディタの上部コンボボックスで選択 → Me.Load
となりました。
只単にデザイナのバグ(不統一)なだけですか。それなら気にしなくていいようですね。
統一したいならフォーム上でダブルクリックしないようにしなければいけませんね。
ちなみに基底クラスのその基底クラスのイベントをハンドルって言う意味で
MyBase.MyBase.Load って書いてみましたがエラーになりました。
1つ上にしか遡れないのですね。それなら余計に MyBase.Load が不自然に思えてきました。 -
コリン星人さん、こんにちは。
コリン星人 さんからの引用 ちなみに基底クラスのその基底クラスのイベントをハンドルって言う意味でMyBase.MyBase.Load って書いてみましたがエラーになりました。 System.Windows.Forms.Form から継承されたフォームから見て、
MyBase の MyBase は ContainerControl に当たりますから、
そもそも Load イベントというのは存在しません。かといって、MyBase.MyBase と書いた時点でコンパイラに怒られますので、
上記が正しいとか正しくない以前の問題ですけども...1つ上にしか遡れないのですね。それなら余計に MyBase.Load が不自然に思えてきました。 VB7.1 以前は、MyBase でないとコンパイル エラーとなるため、
MyBase に統一した方が良い、と私は考えています。 -
まどか さんからの引用
書けたとしても、Form.Loadなのでエラーでしょう。(Control.Enterならとおりそうですけど)じゃんぬねっと さんからの引用
System.Windows.Forms.Form から継承されたフォームから見て、
MyBase の MyBase は ContainerControl に当たりますから、
そもそも Load イベントというのは存在しません。
上記のテスト(MyBase.MyBase.Load)はSystem.Windows.Forms.Formを継承した
共通カスタマイズフォームをさらに継承したアプリケーションフォームからやっていたのですが駄目でした。(笑)じゃんぬねっと さんからの引用
VB7.1 以前は、MyBase でないとコンパイル エラーとなるため、
MyBase に統一した方が良い、と私は考えています。
そうだったのですか。元々は継承元で実装したイベントと継承先(自クラス)で追加作成したイベントとを
明確に分けていたのかな?
継承元で実装したイベント:MyBase.~
継承先で追加作成したイベント:Me.~
ってな具合に。 -
コリン星人 さんからの引用 そうだったのですか。元々は継承元で実装したイベントと継承先(自クラス)で追加作成したイベントとを
明確に分けていたのかな?
継承元で実装したイベント:MyBase.~
継承先で追加作成したイベント:Me.~
ってな具合に。どちらかと言えば、Form 自身かそれ以外のコントロールかの違いだと思います。
この話は、統一性がないという点である種の不具合と言えるかもしれません。
これだけでなく、コードから追加する場合、デザイナから追加する場合とで、
引数の型の記述が微妙に変わるというのも、昔からずっと残っていますね。コードから追加すると、Object
デザイナから追加すると、System.Objectになったりします。
-
一応、こういうスレッドも見つけました。
MyBase.Load Terminology Question
http://www.dotnet247.com/247reference/msgs/6/34488.aspx要するに、派生クラスにおいてOnLoadメソッドをオーバーライドするということは、基底クラスのLoadイベントの動作を変更するということであり、このため、同じ派生クラスにおいて、MyBase.Loadを使う方が自然ということらしいです。
言い方を変えて私が意訳すれば、派生クラスにおいてLoadイベントの振る舞いを変えたいために、基底クラスのOnLoadメソッドをオーバーライドするのだから、派生クラスにおけるLoadイベントは基底クラスとしてのMyBase.Loadを使う方が感覚的にわかりやすいんじゃないかということです。そんなものかなぁというのが私の感じです。VBな方々はどうなんでしょうか?
-
trapemiya さんからの引用 要するに、派生クラスにおいてOnLoadメソッドをオーバーライドするということは、基底クラスのLoadイベントの動作を変更するということであり、このため、同じ派生クラスにおいて、MyBase.Loadを使う方が自然ということらしいです。
言い方を変えて私が意訳すれば、派生クラスにおいてLoadイベントの振る舞いを変えたいために、基底クラスのOnLoadメソッドをオーバーライドするのだから、派生クラスにおけるLoadイベントは基底クラスとしてのMyBase.Loadを使う方が感覚的にわかりやすいんじゃないかということです。「イベント」は「他のインスタンスからの通知へ反応」してるわけなので、よぉく考えると全部On~でいいようなというか、
自分で自分のイベントを受け取るハンドラ・・・ってなんか違和感がわいてきました。
#Handles MyBase.Loadってインスタンスが2つあるような感じ。。。旧VBでは考えもしなかったけど、基底やら派生やらを考えると(気にしないけど)変な感じですね。
-
MyBase.Load のハンドルと Me.Load のハンドルは同じではないという点を強調して補足をします。
イベントの定義にはオーバライドという概念が無いため、どのクラスで定義されたイベントをハンドルするかが、場合によっては動作の違いに現れます。
(一方、イベントを発生させるために慣例的に作成する On~ は単なるメソッドなので、もちろんオーバーライドやオーバーロードができ、これが On~ を作成する意義の一つかと思います。)例えば Form1 のクラス内に
Public Shadows Event Load As EventHandler
と書いた場合、ハンドル対象によって次のように違いが現れます。
(C# では Shadows に対応する new を書かなければコンパイラがちゃんと警告してくれますが、VB では警告されないんですね...)- MyBase の Load をハンドルする場合 … 通常通り、フォームのロード時にイベントハンドラが呼ばれます。
- Me の Load をハンドルする場合 … フォームのロード時にはイベントハンドラが呼ばれません。
上記のイベントの定義は、新しく作成するイベントの名前が単に既存のイベントと同じというだけで、イベントとしては全く別の(既存とは無関係の)イベントを定義していることになります。
そのため、Me.Load をハンドルする場合、その新しく作成した誰も発生させないイベントをハンドルしていることになるので、上記の違いにつながります。
もちろん、逆に新しく定義した Load イベントをハンドルしたい場合は Me.Load をハンドルし、どこかで RaiseEvent Load(~) します。なぜ現在のようにフォームデザイナでのハンドラ作成とコードエディタ上での作成で異なっているかの推測ですが、前者が対象にするのは(メンバを除けば)常に派生クラスが作成される元のクラスなので、ハンドル先は MyBase が妥当であり、後者が対象にするのはコード上の最終結果なので Me が妥当という判断なのかなぁと考えています。
例えば
Public Event Load2 As EventHandler
と書けば、コードエディタの上のイベント一覧にはちゃんと Load2 が表示されますが、デザイナ側のプロパティのイベント一覧には表示されませんし...(このとき BrowsableAttribute は無関係かと)。 - MyBase の Load をハンドルする場合 … 通常通り、フォームのロード時にイベントハンドラが呼ばれます。