画像ファイル
画像ファイル デリゲートとイベント
VB.NET C#全般
1羊の皮を着た狼 VB.NET
2Form1、Form2の相互参照
3Form1、Form2の相互参照 2
4VB.NET C# データ型の基本
5VB.NET C# 文字列
6VB.NET タイマー精度
7BackgroundWorkerの魅力1..
8BackgroundWorkerの魅力2..
9VB6のタイマー
10コントロールの配列をインデクサ..
11コントロールの配列はジェネリク..
12インデクサ(C#、VB.NET)
13インデクサでBit操作
14Unicode 入門
15デリゲート入門
16マルチスレッド入門
17イベント入門
18デリゲートとイベント
18インターフェースの基本

RichTextBox関係
1RichTextBoxの不思議
2テキスト色付け高速化計画
3VB.NET RichTextBox1
4VB.NET RichTextBox 2

RS-232C関係
1RS-232Cの基礎
2RS-232Cの何が変わった..
3SerialPortクラス
4Unicode(ユニコード)の壁
5マルチスレッドの壁
6RS-232C サンプルコード
7RS-232CのHEXモニタ
8RS-232C 送信モジュール
9RS-232Cのループテスト
10RS-232Cのピンチェンジ..

Socket通信
1C#、VB2005 でSocket通信
2サーバー 複数接続

プロセス間通信
1プロセス間通信(送信側)
2プロセス間通信(受信側)


質問、意見はこちらに
画像ファイル

デリゲートとイベント
テキストエディターで改行を行なうと、改行の前に「↓」が入るものが有る。
これは、
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
{
//元々TextBoxの持つOnTextChangedを上書きする
protected override void OnTextChanged(EventArgs e)
{
//Textの最後が改行でしかも↓が無かったらイベントを発生させる
if (base.Text.EndsWith("\r\n") && !base.Text.EndsWith("↓\r\n"))
{
//A どこを呼び出したら良いのか
}
}
}
(VB.NETのコードは省略)
OnTextChangedを書き換えるのはoverrideキーワードである。

ここまでは書いたので有るがはたと困った、Aのコードはどの様に書いたら良いのだろうか?
この新しいテキストを持ち、この新しいテキストのインスタンスのOnTextChangedから呼び出されるメソドの名前は?
残念ながら、ここから呼び出されるイベント名はもちろんクラス名もまだ決まっていないのである。
決まっていないクラスの未定のイベントをどの様にして呼び出せばよいのか。
そこで登場するのがデリゲートである。
デリゲートは他のクラスの参照を保持する。
下のコードを見て頂きたい、「TextNewline(this, e)」はデリゲートを呼び出している。
この場合引数付けなくても良いが慣例に従って送り手の自分のインスタンスと、標準のイベント引数の EventArgsが渡している。
これだけ宣言しておいて、実際の参照はこのテキストボックスを使用する、フォームの中で設定するので有る。
public class MyTextBox : TextBox
{
//デリゲートの宣言
public delegate void dlgNewLine(object sender, EventArgs e);

public dlgNewLine TxtNewLine;
protected override void OnTextChanged(EventArgs e)
{
//Textの最後が改行でしかも↓が無かったらイベントを発生させる
if (base.Text.EndsWith("\r\n") && !base.Text.EndsWith("↓\r\n"))
TextNewline(this, e);
}
}
さて上のコードで有るが、C#の場合はこれでもイベントを起こすことは可能である。
しかしながらC#にはイベント専用の書き方が有る。
public event dlgNewLine txtNewline;
上の様にデリゲートの宣言にeventキーワードを付ける事で、この変数がイベント処理専用として、 宣言されるのである。
eventキーワードを使って書き換えたコードが下のコードである。
C#コード
using System;
using System.Collections.Generic;
using System.Text;

namespace dele2
{
//TextBoxを継承した新しいTextBoxクラス
public class MyTextBox :System.Windows.Forms.TextBox
{
//デリゲートの宣言
public delegate void dlgNewLine(object sender, EventArgs e);

//デリゲートでイベントを宣言する
public event dlgNewLine TextNewline;

//元々TextBoxの持つOnTextChangedを上書きする
protected override void OnTextChanged(EventArgs e)
{
//本来のイベントを呼び出しておく
base.OnTextChanged(e);

//Textの最後が改行でしかも↓が無かったらイベントを発生させる
if (base.Text.EndsWith("\r\n") && !base.Text.EndsWith("↓\r\n"))
{
//インスタンスが有る場合のみ
if (TextNewline != null)
TextNewline(this, e);
}
}
}
}
VB.2005コード
Public Class MyTextBox : Inherits System.Windows.Forms.TextBox
'デリゲートの宣言
Public Delegate Sub dlgNewLine(ByVal sender As Object, ByVal e As EventArgs)

'デリゲートでイベントを宣言する
Public Event TextNewline As dlgNewLine

'元々TextBoxの持つOnTextChangedを上書きする
Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)

'本来のイベントを呼び出しておく
MyBase.OnTextChanged(e)

'Textの最後が改行でしかも↓が無かったらイベントを発生させる
If MyBase.Text.EndsWith(Environment.NewLine) AndAlso _
Not MyBase.Text.EndsWith("↓" + Environment.NewLine) Then
RaiseEvent TextNewline(Me, e)
End If
End Sub
End Class

上のコードはOnTextChangedをoverride(Overrides)して書き換えている訳だが、下のコードで本来の イベントを呼び出しておかないと、標準のOnTextChangeが起きない、イベントを全て書き換えるのなら 必要は無いが、機能を追加する場合は下のコードの様に元のイベントを呼び出しておく。
C#コード
//本来のイベントを呼び出しておく
base.OnTextChanged(e);
VB2005コード
'本来のイベントを呼び出しておく
MyBase.OnTextChanged(e)


イベントのsubscribe(登録側)
さて次はこの新しいTextBoxを使用するコードで有る。
C#コード
public partial class Form1 : Form
{
MyTextBox mt = new MyTextBox();
public Form1()
{
InitializeComponent();
SuspendLayout();
mt.Size = new Size(200, 100);   //大きさ
mt.Location = new Point(20, 10); //位置
mt.Multiline =true;  //複数行の許可
mt.Parent = this;         //これが無いと表示されない
ResumeLayout();
//イベントの登録
mt.TextNewline += myTextBox1_NewLine;
}

//イベントから呼び出されるプロシジャー
private void myTextBox1_NewLine(object sender, EventArgs e)
{
string txt = mt.Text;//テキスト

//↓を挿入
string newtext = txt.Substring(0, txt.Length - 2) + "↓" + "\r\n";
mt.Text = newtext;

//キャレットを最終文字に
mt.SelectionStart = mt.Text.Length;
}
}
VB2005のコード
Public Class Form1
Public Form1()
Dim mt As MyTextBox = New MyTextBox()

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal
e As System.EventArgs) Handles MyBase.Load
SuspendLayout()
mt.Size = New Size(200, 100) '大きさ
mt.Location = New Point(20, 10) '位置
mt.Multiline = True '複数行の許可
mt.Parent = Me 'これが無いと表示されない
ResumeLayout()

'イベントの登録
AddHandler mt.TextNewline, AddressOf myTextBox1_NewLine
End Sub

'イベントから呼び出されるプロシジャー
Private Sub myTextBox1_NewLine(ByVal sender As Object, ByVal e As EventArgs)

Dim txt As String = mt.Text 'テキスト

'↓を挿入
Dim newtext As String = txt.Substring(0, txt.Length - 2) + "↓" _
+ Environment.NewLine
mt.Text = newtext

'キャレットを最終文字に
mt.SelectionStart = mt.Text.Length
End Sub
End Class
新しい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#のコード
//インスタンスが有る場合のみ
if (TextNewline != null)
TextNewline(this, e);
言語仕様の違いは他にも有る、C#の場合eventキーワードを使用せずに、
C#コード
//デリゲートでイベントを宣言する
public dlgNewLine TextNewline;
と書いても正常に動作する、C#の場合eventはデリゲートの特殊形なのだろう。
VB2005はこれは出来ない。

イベントとは
イベントとは何であろうか?
イベントはその書き方からしても、デリゲートのリストを保持するクラス内のフィールドであると言えます。
リストに加える為には、C#は
C#
mt.TextNewline += myTextBox1_NewLine;
の様に「+=」演算子を使い、VB.NETは
VB.NET
AddHandler mt.TextNewline, AddressOf myTextBox1_NewLine
の様に「AddHandler」を使用します。
リスト登録されたデリゲートは登録順に実行されることになるのです。
更にC#は登録されたデリゲートを「-=」演算子で削除することも出来ます。


画像ファイル