none
イベントハンドラについて RRS feed

  • 質問

  • 以前から漠然と疑問に思っていることがあります。

    フォームのイベントハンドラなどで例えば



        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内でイベントをオーバーライドしているわけでもないのにこの違いがよく理解できません。
    敢えて異なることに何か意味があるのでしょうか?

    2006年10月11日 2:33

すべての返信

  • Handlesのヘルプを見る限りどちらでもいいようです。

    ちなみに、
    ・デザイナでフォームをダブルクリック → MyBase.Load
    ・コードエディタの上部コンボボックスで選択 → Me.Load
    となりました。

    2006年10月11日 5:04
  •  まどか さんからの引用

    ・デザイナでフォームをダブルクリック → MyBase.Load
    ・コードエディタの上部コンボボックスで選択 → Me.Load
    となりました。

    只単にデザイナのバグ(不統一)なだけですか。それなら気にしなくていいようですね。
    統一したいならフォーム上でダブルクリックしないようにしなければいけませんね。
    ちなみに基底クラスのその基底クラスのイベントをハンドルって言う意味で
    MyBase.MyBase.Load って書いてみましたがエラーになりました。
    1つ上にしか遡れないのですね。それなら余計に MyBase.Load が不自然に思えてきました。
    2006年10月11日 6:24
  •  コリン星人 さんからの引用

    MyBase.MyBase.Load って書いてみましたがエラーになりました。

    MyBaseはキーワードですからね。>メンバではない。
    書けたとしても、Form.Loadなのでエラーでしょう。(Control.Enterならとおりそうですけど)

    2006年10月11日 7:00
  • コリン星人さん、こんにちは。

     コリン星人 さんからの引用
    ちなみに基底クラスのその基底クラスのイベントをハンドルって言う意味でMyBase.MyBase.Load って書いてみましたがエラーになりました。

    System.Windows.Forms.Form から継承されたフォームから見て、
    MyBase の MyBase は ContainerControl に当たりますから、
    そもそも Load イベントというのは存在しません。

    かといって、MyBase.MyBase と書いた時点でコンパイラに怒られますので、
    上記が正しいとか正しくない以前の問題ですけども...

    1つ上にしか遡れないのですね。それなら余計に MyBase.Load が不自然に思えてきました。

    VB7.1 以前は、MyBase でないとコンパイル エラーとなるため、
    MyBase に統一した方が良い、と私は考えています。

    2006年10月11日 7:07
  •  まどか さんからの引用

    書けたとしても、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.~
    ってな具合に。

    2006年10月11日 9:36
  •  コリン星人 さんからの引用
    そうだったのですか。元々は継承元で実装したイベントと継承先(自クラス)で追加作成したイベントとを
    明確に分けていたのかな?
    継承元で実装したイベント:MyBase.~
    継承先で追加作成したイベント:Me.~
    ってな具合に。

    どちらかと言えば、Form 自身かそれ以外のコントロールかの違いだと思います。

    この話は、統一性がないという点である種の不具合と言えるかもしれません。
    これだけでなく、コードから追加する場合、デザイナから追加する場合とで、
    引数の型の記述が微妙に変わるというのも、昔からずっと残っていますね。

    コードから追加すると、Object
    デザイナから追加すると、System.Object

    になったりします。

    2006年10月11日 9:45
  • 一応、こういうスレッドも見つけました。

    MyBase.Load Terminology Question
    http://www.dotnet247.com/247reference/msgs/6/34488.aspx

    要するに、派生クラスにおいてOnLoadメソッドをオーバーライドするということは、基底クラスのLoadイベントの動作を変更するということであり、このため、同じ派生クラスにおいて、MyBase.Loadを使う方が自然ということらしいです。
    言い方を変えて私が意訳すれば、派生クラスにおいてLoadイベントの振る舞いを変えたいために、基底クラスのOnLoadメソッドをオーバーライドするのだから、派生クラスにおけるLoadイベントは基底クラスとしてのMyBase.Loadを使う方が感覚的にわかりやすいんじゃないかということです。

    そんなものかなぁというのが私の感じです。VBな方々はどうなんでしょうか?

    2006年10月12日 1:06
    モデレータ
  •  trapemiya さんからの引用

    要するに、派生クラスにおいてOnLoadメソッドをオーバーライドするということは、基底クラスのLoadイベントの動作を変更するということであり、このため、同じ派生クラスにおいて、MyBase.Loadを使う方が自然ということらしいです。
    言い方を変えて私が意訳すれば、派生クラスにおいてLoadイベントの振る舞いを変えたいために、基底クラスのOnLoadメソッドをオーバーライドするのだから、派生クラスにおけるLoadイベントは基底クラスとしてのMyBase.Loadを使う方が感覚的にわかりやすいんじゃないかということです。

    「イベント」は「他のインスタンスからの通知へ反応」してるわけなので、よぉく考えると全部On~でいいようなというか、
    自分で自分のイベントを受け取るハンドラ・・・ってなんか違和感がわいてきました。
    #Handles MyBase.Loadってインスタンスが2つあるような感じ。。。

    旧VBでは考えもしなかったけど、基底やら派生やらを考えると(気にしないけど)変な感じですね。

    2006年10月12日 2:50
  • 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 は無関係かと)。

    2006年10月12日 5:56
  •  TH01 さんからの引用

    前者が対象にするのは(メンバを除けば)常に派生クラスが作成される元のクラスなので、ハンドル先は MyBase が妥当であり、後者が対象にするのはコード上の最終結果なので Me が妥当という判断なのかなぁと考えています。

    これは私も思うところです。
    基本クラスで扱わなきゃツールとして振舞えんだろな、と。

    でも、コード生成機能ってことで言えばMe.Loadで生成してもいいんじゃないの?とも思います。

    2006年10月12日 6:06