デリゲートとイベント | |
|
デリゲートとイベント
テキストエディターで改行を行なうと、改行の前に「↓」が入るものが有る。
これは、 C# は textBox1_TextChanged VB.NETはTextBox1_TextChanged イベント内に改行の前に「↓」を入れる処理を書けば良いだけであるが、今回は少しひねって、 TextBoxクラスを継承した新しいTextBoxクラスを作成し、それに文末が改行で有ったらイベントで 知らせるコードを追加してみよう。 先ず開発環境を起動して、空のフォームを作り、プルダウンメニューの「プロジェクト」−> 「クラスの追加」で新しいクラスを追加する。 そして同じ名前空間で、TextBoxクラスから継承された新しいTextBoxクラスを作る。
イベントのpublish(発行側)
TextBoxを継承したクラスを作成する。
C#のコード
public class MyTextBox : System.Windows.Forms.TextBox
VB.NETのコード
Public Class MyTextBox : Inherits System.Windows.Forms.TextBox
C#もVB.NETも殆ど変わりは無いが、VB.NETには Inherits キーワードが付くので注意しよう。
さてこの新しいテキストボックスの中で、本来TextBoxが持つOnTextChangedを書き換えて 新しいイベントを作成しよう。 C#コード
public class MyTextBox : System.Windows.Forms.TextBox
(VB.NETのコードは省略)
OnTextChangedを書き換えるのはoverrideキーワードである。 ここまでは書いたので有るがはたと困った、Aのコードはどの様に書いたら良いのだろうか? この新しいテキストを持ち、この新しいテキストのインスタンスのOnTextChangedから呼び出されるメソドの名前は? 残念ながら、ここから呼び出されるイベント名はもちろんクラス名もまだ決まっていないのである。 決まっていないクラスの未定のイベントをどの様にして呼び出せばよいのか。 そこで登場するのがデリゲートである。 デリゲートは他のクラスの参照を保持する。 下のコードを見て頂きたい、「TextNewline(this, e)」はデリゲートを呼び出している。 この場合引数付けなくても良いが慣例に従って送り手の自分のインスタンスと、標準のイベント引数の EventArgsが渡している。 これだけ宣言しておいて、実際の参照はこのテキストボックスを使用する、フォームの中で設定するので有る。 public class MyTextBox : TextBox
さて上のコードで有るが、C#の場合はこれでもイベントを起こすことは可能である。
しかしながらC#にはイベント専用の書き方が有る。
public event dlgNewLine txtNewline;
上の様にデリゲートの宣言にeventキーワードを付ける事で、この変数がイベント処理専用として、
宣言されるのである。
eventキーワードを使って書き換えたコードが下のコードである。 C#コード
using System; VB.2005コード
Public Class MyTextBox : Inherits System.Windows.Forms.TextBox
上のコードはOnTextChangedをoverride(Overrides)して書き換えている訳だが、下のコードで本来の
イベントを呼び出しておかないと、標準のOnTextChangeが起きない、イベントを全て書き換えるのなら
必要は無いが、機能を追加する場合は下のコードの様に元のイベントを呼び出しておく。
C#コード
//本来のイベントを呼び出しておく VB2005コード
'本来のイベントを呼び出しておく
イベントのsubscribe(登録側)
さて次はこの新しいTextBoxを使用するコードで有る。
C#コード
public partial class Form1 : Form VB2005のコード
Public Class Form1
新しいTextBoxは全てコードで作成している、「SuspendLayout()」「 ResumeLayout()」の間で有る。
VSのバージョンによっては、MyTextBoxクラスを作成して一度Buildすると、ツールボックスの中に MyTextBoxが表示される物も有るが、其の場合は其のコントロールをFormの上に置けば良いことになる。 ここで注意するのはmt.Parent = this(mt.Parent = Me)である、この一行が無いとTextBoxは表示されない。
下のコードは何であろうか?
クラスにイベントを追加した後もし、 mt.TextNewline += myTextBox1_NewLine; 上のコードを追加しないで、このイベントを拾わなかった場合はどうなるのであろうか? C#の場合「オブジェクト参照がオブジェクト インスタンスに設定されていません。」と言うランタイムエラーが出る。 「if」以下はこれを避けるために、インスタンスが作成されていなければ、イベントは起こさない為である。 C#とVB2005の言語仕様の違いでVB2005はイベントを起こして、たとえそれを拾わなくてもエラーにはならない。 C#とVB2005では微妙にコードの仕様が異なる。 C#のコード
//インスタンスが有る場合のみ
言語仕様の違いは他にも有る、C#の場合eventキーワードを使用せずに、
C#コード
//デリゲートでイベントを宣言する
と書いても正常に動作する、C#の場合eventはデリゲートの特殊形なのだろう。
VB2005はこれは出来ない。
イベントとは
イベントとは何であろうか?
イベントはその書き方からしても、デリゲートのリストを保持するクラス内のフィールドであると言えます。 リストに加える為には、C#は C#
mt.TextNewline += myTextBox1_NewLine;
の様に「+=」演算子を使い、VB.NETは
VB.NET
AddHandler mt.TextNewline, AddressOf myTextBox1_NewLine
の様に「AddHandler」を使用します。
リスト登録されたデリゲートは登録順に実行されることになるのです。 更にC#は登録されたデリゲートを「-=」演算子で削除することも出来ます。 |