C# 入門講座
Visual Studio 2005 Visual Studio 2008 Visual Studio 2010 Visual Studio 2012 Visual Studio 2013 Visual Studio 2015 Visual Studio 2017 Visual Studio 2019 Visual Studio 2022

第4回 イベントを逃すな

2021/12/26

この記事が対象とする製品・バージョン

Visual Studio 2022 Visual Studio 2022 対象です。
VS2019 Visual Studio 2019 対象です。
VS2017 Visual Studio 2017 対象です。
VS2015 Visual Studio 2015 対象です。
VS2013 Visual Studio 2013 対象です。
VS2012 Visual Studio 2012 対象ですがそこそこ画面が異なる場合があります。
VS2010 Visual Studio 2010 対象ですがそこそこ画面が異なる場合があります。
VS2008 Visual Studio 2008 対象ですがそこそこ画面が異なる場合があります。
VS2005 Visual Studio 2005 対象ですがそこそこ画面が異なる場合があります。
VS.NET 2003 Visual Studio 2003 対象外ですがほとんどの操作は同じなので参考になります。
VS.NET 2002 Visual Studio (2002) 対象外ですがほとんどの操作は同じなので参考になります。

 

目次

  

1.どこにプログラムするのか

 

今回、 入門講座の第4回では「イベント」について説明します。前回の「プロパティ」と今回の「イベント」の概要が分かれば、あともう少しで最低限必要な知識はそろいます。がんばって習得しましょう。

たとえば、画像を表示するプログラムを作りたいと思ったとしましょう。C#で画像を表示させる方法はインターネット等で検索すればすぐ分かります。多分次のようなコード(プログラム)を発見することでしょう。


this.BackgroundImage = Image.FromFile(@"C:\Windows\Web\Wallpaper\Windows\img0.jpg");

■リスト1

this (読み方:this = ディス)はこの場合はフォームのことです。BackgroundImage(読み方:BackgroudImage = バックグラウンドイメージ)は 背景画像をあらわすプロパティです。

このプログラムの詳細はよくわからないと思いますが、とりあえずコピー&貼り付けしてファイル名だけ変更して実行してみたいと思うことでしょう。でも、このプログラムを一体どこに貼り付ければよいのでしょうか?

イベント」はこういう時の考え方の1つです。これを読んでいる方はまだイベントについて何も知らないはずなので、丁寧に順を追って説明しましょう。

問題は「画像をいつ、どのタイミングで表示したいか?」ということです。

Windows フォーム アプリで、 フォームが表示されたときはじめから画像を表示したいのか、それとも、ボタンが押されたときに表示したいのか、それともフォームをクリックしたら表示するのか…などなどです。

このようなタイミングのことを「イベント」といいます。

この例では「フォームが表示された」、「ボタンが押された」、「フォームをクリックした」などがイベントです。そしてイベントごとにプログラムを書く場所はある程度限定されます。

 

2.Clickイベント

では、具体的にプログラムしてみましょう。まずはボタンが押されたときに画像が表示されるようにしましょう。

「ボタンが押された」というイベントはClickイベント (読み方:Click = クリック)と呼びます。

ボタンがクリックされたときに何かを実行するというプログラムは入門講座でも既に登場しています。今回は「イベント」の視点で改めて眺めてみることにします。

 

まず、新しいWindows フォーム アプリを作成してください。

Windows フォーム アプリケーション

■画像1:新しいプロジェクトを作成した直後

 

そしてフォームにボタンを1つ貼り付けてください。

フォームにButtonを1つ貼り付けたところ

■画像2:ボタンを貼り付けた状態

 

このボタンがクリックされたらフォームに画像を表示することにします。

 

ボタンをダブルクリックしてください。そうすると、画面がコードエディターに切り替わります。

この操作はこれまでの入門講座でも何回かやっていますね。

 

ボタンをダブルクリックすることで次のコード(プログラム)が自動的に生成されますので、ボタンをダブルクリックするという手順がとても重要です。

private void button1_Click(object sender, EventArgs e)
{

}

■リスト2:ボタンのClickイベントハンドラー

このプログラムはボタンがクリックされたときに実行されます。これをクリックイベントのイベントハンドラーと呼びます。

 

それではここに先ほどの画像を表示するプログラムを書いてみましょう。

private void button1_Click(object sender, EventArgs e)
{ this.BackgroundImage = Image.FromFile(@"C:\Windows\Web\Wallpaper\Windows\img0.jpg"); }

■リスト:ボタンをクリックするとフォームに C:\Windows\Web\Wallpaper\Windows\img0.jpg を表示する。

ここでは仮に「img0.jpg」という画像ファイルを指定しています。これはWindowsの標準の壁紙なので多くの環境に存在すると思います。画像はパソコンの中にある普通の画像ファイルであればだいたい使えるのでみなさんのお好みの画像を指定してください。指定できる画像の形式はbmp、gif、jpeg、png、tiffです。

実際に実行して試してみてください。

 

ここでのポイントは、

イベントが発生したらイベントハンドラーに記述したプログラムが実行される

ということです。

 

3.イベントハンドラーの作り方

3-1.MouseHoverイベントのイベントハンドラー生成

今度はClickイベント以外のイベントもいくつか使ってみましょう。

コントロールには複数のイベントがあり、ボタンにもざっと数十個のイベントがあります。Clickイベントはその1つですが、ボタンの場合はもっともよく使うイベントなので特別扱いされており、デザイナー上でコントロールをダブルクリックするだけでそのイベントハンドラーが自動生成されるようになっています。

他のコントロールでもデザイナー上でダブルクリックするとコントロールごとにもっとも良く使うであろうイベントのイベントハンドラーが自動生成されるようになっています。

 

それ以外のイベントはプロパティウィンドウで該当するイベントをダブルクリックすることでイベントハンドラーを自動生成します。

プロパティウィンドウにはプロパティの一覧だけではなくイベントの一覧も表示されます。

 

それでは、ボタンのMouseHoverイベント (読み方:MouseHover = マウスホバー) のイベントハンドラーをプログラムしてみましょう。

MouseHoverイベントはマウスカーソルが上に来ると発生するイベントです。クリックしなくてもマウスカーソルを重ねるだけで発生します。

 

デザイン画面に切り替えてbutton1を選択してください。プロパティウィンドウでbutton1が選択されている状態で雷マークのイベントボタンをクリックしてください。

プロパティウィンドウにbutton1で使用できるイベントの一覧が表示されます。

説明どおりにやっている場合、Clickイベントにはイベントハンドラーが表示されていますが、それ以外のイベントには何も設定されていない状態になっています。

 ここでMouseHoverを探して、ダブルクリックしてください。

プロパティウィンドウでMouseHoverをダブルクリック

MouseHoverを選択するとMouseHoverのイベントハンドラーが次のように自動生成されます。

private void button1_MouseHover(object sender, EventArgs e)
{

}

名前に「MouseHover」と入っているのでMouseHoverイベントのイベントハンドラーであるとわかります。ただし、名前を変更する方法もあるので、イベントハンドラーの名前が常にイベントと一致しているというわけではありません。

 

マウスが上に来たらボタンを光らせてみましょう。次のようにプログラムしてください。

private void button1_MouseHover(object sender, EventArgs e)
{
button1.BackColor = Color.Yellow;
}

実行して、ボタンの上にマウスを持っていくと、ボタンの色が黄色くなるのが確認できます。

でも、マウスをボタンの外に移動しても色は元に戻りません。MouseHoverイベントが発生したらボタンの色を黄色にするというプログラムはしているのに、マウスが外にでていったら元の色に戻すというプログラムをしていないからです。マウスが外に出て行くときにはMouseLeaveイベント(読み方:MouseLeave = マウスリーブ)が発生しますからこのイベントを使って、色を元に戻してみることにしましょう。

 

 

3-2.MouseLeaveイベントのイベントハンドラー生成

やることは先ほどと同じです。デザイン画面に切り替えてbutton1を選択してください。プロパティウィンドウでbutton1が選択されている状態でイベントボタンをクリックしてください。

説明どおりにやっている場合、ClickイベントとMouseHoverイベントにはイベントハンドラーが表示されていますが、それ以外のイベントには何も設定されていない状態になっています。

プロパティウィンドウでMouseLeaveイベントを選択する

ここでMouseLeveを探して、ダブルクリックしてください。

そうするとMouseLeaveイベントハンドラーが生成されます。下記のようにプログラムしてください。

private void button1_MouseLeave(object sender, EventArgs e)
{
    button1.BackColor = SystemColors.Control;
    button1.UseVisualStyleBackColor = true; }

元の色がWindowsの視覚スタイルを利用したコントロール用の表示なので、黄色にするときより少しプログラムが増えています。私が説明したいのはイベントなので、このプログラムについては深入りしませんように。

これでマウスがボタンの外に出るとボタンの表示は元に戻ります。1度実行してみてください。

 

3-3.イベントハンドラーとイベントを結びつける仕組み

コントロールをダブルクリックしたり、プロパティウィンドウでイベントをダブルクリックすると自動的にイベントハンドラーのプログラムが生成されるのもう理解されたと思います。

ダブルクリックしたときにもう1つ目には見えない部分で変化が起きています。

それは、イベントとイベントハンドラーを結びつけるプログラムが自動的に作成されている点です。

たとえば、クリックイベントハンドラーとクリックイベントを結びつけるプログラムは次のようになります。

	
this.button1.Click += new System.EventHandler(this.button1_Click);

このプログラムは普段表示されていないForm1.Designer.csというファイルの中に自動的に生成されます。

ソリューションエクスプローラーでForm1.csを展開するとこのファイルの中身を見ることができますが、このファイルの内容は自動的に編集されるので絶対に自分では変更しないでください。また、通常は見る必要もありません。

Visual Studio のバージョンによってはForm1.Designer.cs の中に、「Windows Form Designer generated code」と表示され折りたたまされている部分があり、クリックして展開するとことで上記のプログラムを確認できます。

Form1.Designer.cs

 

3-4.イベントハンドラーの削除と再生成

イベントハンドラーを削除する場合は、自動生成されたイベントハンドラーだけを削除するとエラーになります。このことは第2回でも紹介しています。

たとえば、さきほどClickイベントのイベントハンドラーに下記のように背景に画像を表示するコードをプログラムしました。

private void button1_Click(object sender, EventArgs e)
{ this.BackgroundImage = Image.FromFile(@"C:\Windows\Web\Wallpaper\Windows\img0.jpg"); }

これがいらなくなった場合、private から } までのプログラムを自分で削除してしまうとエラーになります。

Visual Studio 2022の場合は、プログラムを実行しようとして時に、「ビルドエラーが発生しました。」と表示され実行できなくなります。

 

Visual Studio 2019以前の場合は、もっとわかりにくく、デザイン画面に切り替えるだけでも下記のようなエラーが発生します。

なお、デザイン画面のこのようなエラー画面はいろいろな要因で表示されますので、イベントハンドラーを消してしまった以外の原因でこれが同じような画面が表示されることもあります。この画面をみたら表示されているメッセージ(下の画像の場合 『不明な名前 'Button1_Click' を処理できません。』というのが怪しいです)を見て判断するようにしてください。

もちろん、この状態でプログラムを実行しようとしてもエラーになります。

 

Visual Studio 2022の場合も 2019 の場合も、エラーになる理由は、Form1.Designer.csにイベントとイベントハンドラーを結びつけるプログラムが残っているのに、イベントハンドラーだけを削除してしまったため、結びつける対象をVisual Studioが見つけられなくなってしまうからです。

Visual Studio 2019以前の場合、 デザイン画面くらい表示してくれても良さそうに思えますがVisual Studioのデザイナーはこの場合デザイン画面も表示してくれなくなります。Visual Studio 2022ではこの点は解消されて少し使いやすくなったようです。

この状態になってしまったら、元に戻すボタンを押してイベントハンドラーを削除前の状態に戻すのが一番です。一応、Form1.Designer.csのイベントとイベントハンドラーを結び付けているプログラムを自分で削除することでもエラーは解消できますが、さきほど説明したようにForm1.Designer.csを自分で編集することは控えるべきです。(でも、もしベテランの先輩があなたの隣に座ってこれを眺めていたら、その先輩はForm1.Designer.csを編集することでこれを解決してしまうかもしれません。何が危険で、どうすればよいかわかるだけの知識と経験があるのならばそれもOKです。)

元に戻すのがあまりにも大変な場合は、イベントハンドラーを自分で書き直しても良いです。このときイベントハンドラーの中身のプログラムはなくても良いです。とにかく結びつける対象のイベントハンドラーが存在していればよいのです。

 

エラーの説明が長くなってしまいました。初心者がよく困るポイントなので重点的に説明しました。

 

それでは、イベントハンドラーを削除する正しい手順はどのようなものでしょうか?

イベントハンドラーを削除するには、プロパティウィンドウで対象のイベントを右クリックして「リセット」を選択してください。

リセットを行うとイベントとイベントハンドラーの結びつけが解除され、Form1.Designer.cs内のプログラムも除去されます。

リセットする代わりにイベントハンドラーの名前をマウスとキーボードで除去して、Enterを押しても良いです。

 

イベントハンドラー内に何かプログラムが1行でもあればイベントハンドラーは削除されずに残りますが、それはもはやクリックしても動作しないのでイベントハンドラーではなく、いわばイベントハンドラーの残骸であり、名前がイベントハンドラー『風』のプログラムです。

一度リセットした後、やっぱりもう1度イベントハンドラーとして復活させたい場合は、右側の下矢印を展開しましょう。イベントハンドラーになれる候補の一覧が表示されます、この中にはイベントハンドラーの残骸も表示されますので、ここで選択しなおせば、改めてイベントハンドラーとして紐付けされクリックしたときに動作するようになります。

このときに残骸から選択するのではなく、新しいイベントハンドラーを作成した場合は、ダブルクリックするか、自分で新しいイベントハンドラーの名前を入力してEnterキーを押します。

private void MyClickEventHandler(object sender, EventArgs e)
{
   MessageBox.Show("これもクリックイベントのハンドラーになれるんです。"); }

 

残骸が残っている状態でダブルクリックすると元のイベントハンドラー名に連番がついた美しくない名前になりますので私はお勧めしません。

博士のワンポイントレッスン 「コピーしたサンプルが動作しない」
V太 V太:あれ、おかしいなぁ。クリックしても動かない・・・。
B子 B子:どうしたの?
V太 Webサイトに良さそうなサンプルを見つけたんで、コピー・貼り付けしてみたんだけどクリックしても何も起きないんだよ。
B子 あー。それね・・・。ほら、そこのbutton1_Clickってイベントハンドラーなのよね。だからコピーするだけじゃ動かなくて、コピーした後で自分でプロパティウィンドウでイベントと結びつけないといけないんじゃないかしら。
V太 そういうことか!なるほどなるほど。イベントハンドラーはコピーしただけじゃイベントハンドラーになりませんよっと。
V太 でも、いちいちこれやるの面倒じゃないか?コピーだけで動けば楽なのに。
B子 まぁ、どうせボタンは自分で配置するしかないんだから、そのときにイベントハンドラーも結びつければいいんじゃないの?
博士 博士:ふむふむ。Webで公開されているサンプルの中にはコピーだけでイベントハンドラーが動くように特別な仕掛けがされているものもあるぞ。じゃが、そうでないものの方が多いから、自分でイベントハンドラーの結び付けくらいできるようにしておいたほうが良いのぉ。

 

 

4.フォームのイベント

 

フォームにも重要なイベントがいくつかあります。こういったことは「習うより慣れろ」です。どんどんいろんなイベントを使ってみましょう。

Windowsフォーム アプリではアプリケーションはフォームと共に開始し、フォームを閉じると終了します。

開始と終了に関連する主なイベントは次の4つです。

イベント 読み方 発生するタイミング
イベントLoad ロード フォームがはじめて表示される直前に発生します。最初に動かしたい処理はこのタイミングでプログラムします。
イベントShown ショウン フォームが表示された直後に発生します。
イベントFormClosing フォームクロージング フォームが閉じる直前に発生します。この段階ではまだ閉じる操作をキャンセルできる場合があります。
イベントFormClosed フォームクローズド フォームが閉じた直後に発生します。最後に動かしたい処理はこのタイミングでプログラムします。

この他にボタンと同じようにClickイベントやMouseHoverイベントなどもあります。

参考:フォームのイベントの一覧

 

デザイン画面でフォームをダブルクリックするとLoadイベントのイベントハンドラーが生成されます。フォームのイベントの中では最もよく使うイベントで、最初に実行したい処理はこのイベントハンドラーにプログラムします。

今回は練習のため、Shownイベントを使ってみることにします。Shownイベントはフォームが表示された直後に発生します。順番でいうとLoadイベント発生→フォーム表示→Shownイベント発生となります。

イベントハンドラーの生成方法はフォームでもボタンの時と同じです。Shownイベントのイベントハンドラーを生成させてみてください。

 

今は退屈ですが、Shownが発生したという出力だけ記述しておくことにしましょう。次のようにしてください。

private void Form1_Shown(object sender,EventArgs e)
{
    System.Diagnostics.Debug.WriteLine("Shownが発生しました。"); }

System.Diagnostics.Debug.WriteLine (読み方:System = システム、 Disgnostics = ダイアグナスティクス、Debug = デバッグ、WriteLine = ライトライン)はちょっとプログラムの確認をするときに便利な機能です。

これを実行すると、出力ウィンドウに指定したメッセージが表示されます。

出力ウィンドウはプログラムを実行中には右下に表示されています。「出力」というタブをクリックすることで他のウィンドウから切り替わります。

表示されていない場合は、[ウィンドウ]メニューでウィンドウレイアウトをリセットするか、[デバッグ]メニューの[ウィンドウ] - [出力] で表示できます。

実行時の出力ウィンドウ

このウィンドウにはいろいろな情報が表示されるため、出力ウィンドウの上側にある「出力元」という部分で内容を切り替えられます。Debug.WriteLineで書き込んだ内容は「デバッグ」を選択すると表示されます。

実行を停止すると下側に表示されています。

デザイン時の出力ウィンドウ

今度はFormClosingイベントとFormClosedイベントも利用して次のようにプログラムしてみてください。

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
   MessageBox.Show("フォームが閉じました。"); }

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
   MessageBox.Show("フォームが閉じますよ。","FormClosingです。", MessageBoxButtons.OK, MessageBoxIcon.Information); MessageBox.Show("本当に閉じますよ!", "FormClosingです。", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}

これでプログラムを実行してから、フォームの右上の×ボタンでフォームを閉じようとすると3つのメッセージが順番に表示されます。

なお、イベントハンドラー同士はどちらが上にあっても下にあっても実行の順番には影響しません。フォームが閉じる直線に実行されるのがForm1_FormClosingであり、フォームが閉じた直後に実行されるのがForm1_Closedであるというイベントのタイミングに従って実行されます。

イベントハンドラー内のプログラムは基本的には上から下へと順番に実行されます。

 

せっかくなので最初の例で出した画像の表示もプログラムして見ましょう。Form1のLoadイベントに次の通り記述してください。

private void Form1_Load(object sender, EventArgs e)
{
    this.BackgroundImage = Image.FromFile(@"C:\Windows\Web\Wallpaper\Windows\img0.jpg"); }

これでプログラム開始時点から背景に画像が表示されているフォームの完成です。

画像ファイルは実際にみなさんのパソコンに入っているものを指定してください。

 

5.イベントドリブン での 自動処理

5-1.イベントドリブン

ここまでの説明で、「どこにプログラムしたらよいのか?」ということはだいたい分かっていただけたと思います。

処理したいタイミングで実行される部分にプログラムするというのが正解です。

Windowsフォームアプリの場合は、イベントによって処理が起動されるので、イベントハンドラーに記述するということです。

このようにイベントが発生するとそれに対応するイベントハンドラーに記述された処理が実行されるという仕組みを イベントドリブン と呼びます。日本語で言うところのイベント駆動という意味です。

Windowsフォームアプリは基本的にイベントドリブンです。

 

5-2.Timerコンポーネント

イベントにはさまざまな種類があり、中には「時間が経った」というイベントもありますから、イベントドリブンでもユーザーの操作を待つことなく何か処理を実行することも可能です。

Windowsフォームアプリケーションで、ゲームのように自動的にどんどん進行していくプログラムを作るには、Timer コンポーネント(読み方:Timer = タイマー)を使うのをお勧めします。

ここで言う「コンポーネント」とはコントロールと同じようなものなのだけど目には見えないものを指しています。TimerコンポーネントはButtonと同じようにツールボックスから配置できます。コンポーネントタブ(英語の場合はComponentsタブ)にあります。ただし実行時には目に見えません。

Timerコンポーネントには時間が経つと発生する Tick (読み方:Tick = ティック)というイベントがあります。どのくらい時間が経つとTickイベントが発生するかはIntervalプロパティ(読み方:Interval = インターバル)で設定できます。

ためしにフォームにTimerコンポーネントを配置してみましょう。コンポーネントは配置するとフォームの下側に表示されます。

Timerコンポーネントがフォームの下側に表示されている

次にプロパティウィンドウを使ってEnabledプロパティの値が確認してください。もし、TrueになっていなければTrueに(読み方:True = トゥルー)してください。(以前のバージョンでは初期状態が True になっていないので念のため確認してほしいということです。)

Enabledプロパティは有効/無効の状態を表しています。Trueとはプログラムでは良く出てくるとても重要な値で、「オン」や「有効」、「はい」などの肯定的な意味があります。つまり、EnabledプロパティをTrueにするということの意味はタイマーを有効にするという意味です。

なお、Trueの反対語はFalse(読み方:False = フォルス)です。こちらは「オフ」や「無効」、「いいえ」などの否定的な意味になります。

 

次にIntervalプロパティを 1000 に設定してください。これは1秒ごとにTickイベントを発生させることを意味します。もし、500に設定すると0.5秒ごとにTickイベントが発生します。このように秒の千分の一表す単位を「ミリ秒」と呼びます。

もう1つ、FormのTextプロパティを 0 に設定してください。

まとめると設定すべきプロパティは次の通りです。

コントロール プロパティ
イベントTimer1 イベントEnabled True
  イベントInterval 1000
イベントForm イベントText 0

 

そして、Tickイベントハンドラーに次のように記述してみてください。

private void Timer1_Tick(object sender, EventArgs e)
{
   this.Text = (int.Parse(this.Text) + 1).ToString(); }

プログラムの内容は今回は説明しませんが、簡単に書くとこのプログラムは this.TextTickイベントが発生するたびに +1 するものです。フォームのプログラムではthisとはフォームのことで、そのTextプロパティはタイトルバーに表示されている一連の文字(たとえば「Form1」)を指します。Parse(読み方:Parse = パース)とかToString(読み方:ToString = トゥーストリング)は、値の型を変換するなどしているのですが、型については今後の入門講座で扱います。

実行すると、1秒ごとにタイトルバーがカウントアップしていきます。

 

このようにTimerを使うと自動的にどんどん処理が進んでいくというプログラムをイベントを使って記述することができます。

なお、TimerIntervalプロパティはミリ秒単位なので1秒の1000分の1の細かさで指定できますが、あまり精度は高くなく、細かい値を設定しても正確にその通り動いてくれるわけではありません。あくまでTickイベントを発生させるための目安の時間として使ってください。このTimerを利用して時間測定などはしないほうが良いです。

 

次の回では、メソッドを使って処理を呼び出す方法と、プログラムでプロパティを操作する方法を説明します。

C#入門講座 第5回 メソッドとプロパティ