C#ならボタンがクリックされたとかキーが押されたなどのイベントが発生したらどんな処理をするのかという感じでプログラミングしていきます。イベントは既存のものだけでなく自分で定義することもできます。
例としてメインのフォームとは別にもうひとつフォームを生成します。そしてふたつめのフォームでマウスボタンが押下されたらそれをメインのフォームに伝えて、クリックした旨を表示させます。
それだけなら自分でイベントを実装する必要はありません。これで充分なはずです。
Form1のボタンをクリックしたらForm2が出現します。そしてForm2のクライアント領域をクリックするとクリックされた座標がコンソールに表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MouseDown += _form2_MouseDown; } private void button1_Click(object sender, EventArgs e) { _form2.ShowDialog(); } private void _form2_MouseDown(object sender, MouseEventArgs e) { Console.WriteLine($"Form2.MouseDownイベント:クリックされた座標は({e.X},{e.Y})"); } } |
イベントを自分で定義する
ただ、ここでは自分でイベントを実装したいので、あえて面倒な方法をとります。いわばサンプルプログラムです。
Form2クラス側でクライアント領域がクリックされたことを、自分で実装したイベントでForm1クラスに伝えるだけならこれで充分です。
ただこれではForm2のどこがクリックされたのかを伝えることができません。ただクリックされたことを伝えることができるだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public partial class Form2 : Form { public event EventHandler MyEvent1; protected override void OnMouseDown(MouseEventArgs e) { MyEvent1?.Invoke(this, new EventArgs()); base.OnMouseDown(e); } } public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MyEvent1 += _form2_MyEvent1; } private void _form2_MyEvent1(object sender, EventArgs e) { Console.WriteLine($"Form2.MyEvent1イベント:クリックされた"); } } |
イベントハンドラで値を取得できるようにする
そこでクリックされた座標もイベントハンドラで取得できるようにします。
まずEventArgsを継承してMyEventArgsクラスを定義します。コンストラクタに座標を渡せばどこがクリックされたのかをForm1クラスに伝えることができます。
MyEvent2?.Invokeの第二引数にEventArgsのインスタンスではなくMyEventArgsのインスタンスを渡しているのでイベントハンドラでMyEventArgsにキャストしなければクリックされた座標を取得することができません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public class MyEventArgs : EventArgs { public MyEventArgs(Point point) { Point = point; } public Point Point { get; } } public partial class Form2 : Form { public event EventHandler MyEvent2; protected override void OnMouseDown(MouseEventArgs e) { Point point = new Point(e.X, e.Y); MyEventArgs args = new MyEventArgs(point); MyEvent2?.Invoke(this, args); base.OnMouseDown(e); } } public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MyEvent2 += _form2_MyEvent2; } private void _form2_MyEvent2(object sender, EventArgs e) { MyEventArgs args = (MyEventArgs)e; Console.WriteLine($"Form2.MyEvent2イベント:クリックされた座標は({args.Point.X},{args.Point.Y})"); } } |
デリゲートを宣言してイベントハンドラで自由にデータを取得できるようにする
イベントを送信するときMyEvent?.Invoke(object sender, EventArgs e);のような形にするのが一般的ですが、第二引数はEventArgs型でなければならないのかというとそうではありません。好きな型を渡すことができます。ただし、この場合はイベントを定義するときに以下のような処理をいれる必要があります。
|
public delegate void MyEvent3Handler(object sender, MyEventArgs e); public event MyEvent3Handler MyEvent3; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public partial class Form2 : Form { public delegate void MyEvent3Handler(object sender, MyEventArgs e); public event MyEvent3Handler MyEvent3; protected override void OnMouseDown(MouseEventArgs e) { Point point = new Point(e.X, e.Y); MyEventArgs args = new MyEventArgs(point); MyEvent3?.Invoke(this, args); } } public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MyEvent3 += _form2_MyEvent3; } private void _form2_MyEvent3(object sender, MyEventArgs e) { Console.WriteLine($"Form2.MyEvent3イベント:クリックされた座標は({e.Point.X},{e.Point.Y})"); } } |
イベントハンドラの引数は自由に設定できる
さらに言ってしまうとMyEvent?.Invoke(object sender, EventArgsまたはそれを継承したクラス e);というような引数の型に縛りがあるわけでもありません。こんなイベントを実装することもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public partial class Form2 : Form { public delegate void MyEvent4Handler(int x, int y); public event MyEvent4Handler MyEvent4; protected override void OnMouseDown(MouseEventArgs e) { MyEvent4?.Invoke(e.X, e.Y); base.OnMouseDown(e); } } public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MyEvent4 += _form2_MyEvent4; } private void _form2_MyEvent4(int x, int y) { Console.WriteLine($"Form2.MyEvent4イベント:クリックされた座標は({x},{y})"); } } |
MyEvent?.Invoke();の引数ですが、2個でなければならないという縛りもありません。こんなのもありです。
下記のコードならクリックされた座標だけでなくクリックされた時刻や回数も取得できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
public partial class Form2 : Form { public Form2() { InitializeComponent(); } int _count = 0; public delegate void MyEvent5Handler(int x, int y, DateTime time, int count); public event MyEvent5Handler MyEvent5; protected override void OnMouseDown(MouseEventArgs e) { _count++; MyEvent5?.Invoke(e.X, e.Y, DateTime.Now, _count); base.OnMouseDown(e); } } public partial class Form1 : Form { Form2 _form2 = new Form2(); public Form1() { InitializeComponent(); _form2.MyEvent5 += _form2_MyEvent5; } private void _form2_MyEvent5(int x, int y, DateTime time, int count) { string s1 = $"クリックされた座標は({x},{y})"; string s2 = $"時刻は{time.ToLongTimeString()}"; string s3 = $"{count}回目のクリックです"; Console.WriteLine($"Form2.MyEvent5イベント:{s1}。{s2}。{s3}。"); } } |
鳩でも分かるC#管理人からのお願い
できる仕事であれば請け負います。鳩でもわかるC#管理人はクラウドワークスに在宅ワーカーとして登録しています。お仕事の依頼もお待ちしております。
⇒ 仕事を依頼する
コメントについて
コメントで英語などの外国語でコメントをされる方がいますが、管理人は日本語以外はわからないので基本的に内容が理解できず、承認することもありません。それからへんな薬を売っているサイトやリンク先のサイトが存在しないというスパムコメントも多々あります。
Some people make comments in foreign languages such as English, but since the manager does not understand anything other than Japanese, he basically cannot understand the content and does not approve it. Please use Japanese when making comments.
そんななか日本語のコメントもいただけるようになりました。「○○という変数はどこで宣言されているのか?」「××というメソッドはどこにあるのか」「例外が発生する」「いっそのことソース丸ごとくれ」という質問ですが、管理人としては嬉しく思います。「自分が書いた記事は読まれているんだな」と。疑問点には可能な限り答えます。記事に問題があれば修正いたします。
そのうえでお願いがあります。「匿名」という味も素っ気もない名前ではなく、捨てハンでいいのでなにかハンドルネームをつくってほしいと思います。
管理人のモチベーションアップのために
よろしければご支援お願いします。
⇒ 管理人の物乞いリスト
delegateは何回見ても覚えられなかったのですが、
今回は、大変勉強になりました。