GitHub Desktopで見てみよう ― WinFormsでボタンを置くと、裏では何が変わる?

広告

Visual StudioのWinFormsデザイナーでは、ツールボックスからButtonやLabelをドラッグ&ドロップするだけで画面を作れます。

しかし、そのときC#のコードでは何が起きているのでしょうか。

今回は、Visual Studioで少しずつ画面を作り、そのたびにGitHub Desktopで差分を確認することで、WinFormsの仕組みとGitの「差分」を同時に見ていきます。

WinFormsで操作すると裏側でコードが追加される流れの概念図(Button配置、Label追加、Clickイベント追加、実行結果)
今回の実験の全体像(概念図)。実際にどの行が追加・削除・変更なしになるかは、このあとのGitHub Desktopのキャプチャーで確認していきます。

GitHub Desktopの「差分」とは?

GitHub Desktopでは、前回コミットした状態からファイルがどのように変化したのかを確認できます。

基本的には、

  • 緑(行頭が +):追加された部分
  • 赤(行頭が -):削除された部分
  • 白(記号なし):変更されていない部分(変更箇所の前後が参考として表示されます)

として表示されます。

大切なのは、GitがVisual Studioで行った操作を記録しているわけではないことです。

たとえばGitは、

「ツールボックスからButtonをドラッグした」

という操作を知りません。

Gitが見ているのは、あくまで

操作の結果、ファイルの内容がどう変わったか

です。

この特徴を利用して、WinFormsデザイナーが裏で何をしているのか観察してみましょう。

1.まずButtonを1個置いてみる

空のFormをコミットしておき、そこにButtonを1個配置します。

GitHub Desktopで Form1.Designer.cs の差分を見ると、多くのコードが追加されていることが分かります。

Buttonを1個配置したときのForm1.Designer.csの差分
Buttonを1個置いただけで、Form1.Designer.csにこれだけのコードが追加される

まず、Buttonが生成されています。

button1 = new Button();

デザイナーでは単にButtonをドラッグしただけですが、C#ではButtonクラスからオブジェクトを生成しています。

そして、さまざまなプロパティが設定されます。

button1.Location = new Point(325, 199);
button1.Name = "button1";
button1.Size = new Size(150, 46);
button1.TabIndex = 0;
button1.Text = "button1";
button1.UseVisualStyleBackColor = true;

デザイナー上で見えていた「位置」「大きさ」「表示文字」などは、実際にはこのようなプロパティの値として保存されています。

各プロパティの意味(クリックで開く)
  • Location:フォームの左上を (0, 0) としたときの、コントロールの左上の位置です。Point(325, 199) は、右に325、下に199の位置を表します。
  • Name:コードの中でこのコントロールを呼ぶための名前です。プロパティウィンドウの (Name) を変えると、フィールド名 button1 も変わります。
  • Size:コントロールの幅と高さです。Size(150, 46) は、幅150・高さ46を表します。
  • TabIndex:Tabキーを押したときに、フォーカスが移動する順番です。置いた順に0、1、2…と振られるので、あとから置いたlabel1は1になっています。
  • Text:画面に表示される文字です。
  • UseVisualStyleBackColortrue のときは、Windows標準のボタンの見た目で背景が描かれます。デザイナーで BackColor を変更すると、通常は自動的に false になります。

特に NameText は混同しやすいので注意しましょう。Name はプログラムの中で使う名前、Text は画面に表示される文字です。

さらに重要なのが、次のコードです。

Controls.Add(button1);

Buttonnewしただけでは、Form上には表示されません。

生成したButtonをFormのControlsコレクションに追加することで、Formの中にButtonが配置されます。

最後にフィールドも追加されています。

private Button button1;

つまり、デザイナーで行った、

「Buttonを1個置く」

という操作は、コードとして考えると、

Buttonを生成 → プロパティを設定 → FormのControlsに追加

という処理だったことが分かります。

補足:赤い行(削除)にも注目

差分の先頭をよく見ると、1行だけ赤く表示されている行があります。

components = new System.ComponentModel.Container();

差分の先頭では、空のFormにあった components = new System.ComponentModel.Container(); が削除されています。Designer.csはVisual Studioによって自動生成・更新されるため、コントロールの追加などをきっかけに、今回直接操作していない行も変更されることがあります。

また、SuspendLayout();ResumeLayout(false); も追加されています。これは「コントロールの設定が終わるまで、画面のレイアウト計算をいったん止めておく」ための処理です。1つずつ設定するたびに再計算しないよう、デザイナーがまとめて囲んでくれています。

このように、差分では追加(緑)だけでなく削除(赤)も同時に起きることがあります。

ここはGitを学ぶうえでも大切なポイントです。自分が直接書いていないところまで、差分に出ることがあります。だからこそ、コミットする前にGitHub DesktopのChangesで「何が変わったのか」を確認する習慣が役に立ちます。

2.次にLabelを1個追加してみる

Buttonを置いた状態をいったんコミットします。

その後、Labelを1個追加して、もう一度GitHub Desktopを確認します。

今度はLabelを追加したことによる差分だけを見ることができます。

Labelを追加したときのForm1.Designer.csの差分
Labelを追加したときの差分。Buttonのコードはコミット済みなので白(変更なし)で表示される

Buttonのコードはすでにコミットされているため白(変更なし)で表示され、Labelに関する行だけが緑になっているのが分かります。

最初にLabelが生成されます。

label1 = new Label();

続いてプロパティが設定されています。

label1.AutoSize = true;
label1.Location = new Point(365, 288);
label1.Name = "label1";
label1.Size = new Size(78, 32);
label1.TabIndex = 1;
label1.Text = "label1";
Buttonとの違い(クリックで開く)
  • AutoSize = true が増えている:文字の長さに合わせて大きさが自動で決まります。Size(78, 32) は自分で決めた値ではなく、自動で計算された値です。
  • UseVisualStyleBackColor がない:Buttonにあったプロパティが、Labelでは生成されていません。クラスが違えば、持っているプロパティも違うことが分かります。
  • TabIndex = 1 が付いている:Labelは、Tabキーでフォーカスを受け取りません。それでも番号が振られるのは、アクセスキー(& を付けた文字)を押したときに、次の番号のコントロールへフォーカスを渡すためです。

そしてFormに追加されます。

Controls.Add(label1);

フィールドも追加されました。

private Label label1;

Buttonのときとほとんど同じですね。

なお、Labelは AutoSize = true(文字の長さに合わせて大きさが自動で変わる)なので、レイアウトを確定させるための PerformLayout(); も追加されています。

整理すると、

Button
  ↓
new Button()
  ↓
プロパティを設定
  ↓
Controls.Add(button1)

Label
  ↓
new Label()
  ↓
プロパティを設定
  ↓
Controls.Add(label1)

となっています。

ここから、ButtonもLabelも特別な「絵」ではなく、C#のクラスから生成されたオブジェクトだということが見えてきます。

3.ButtonのClickイベントを追加してみる

次はButtonをクリックしたときに、Labelの文字を変更してみます。

デザイナーでButtonをダブルクリックし、作成されたbutton1_Clickに次の処理を書きました。

private void button1_Click(object sender, EventArgs e)
{
    label1.Text = "ボタンを押した";
}

GitHub Desktopを見ると、今までとは少し違うことに気付きます。

今回は2つのファイルが変更されています

Form1.Designer.csの変更

Form1.Designer.csには、次の1行が追加されています。

Clickイベント追加時のForm1.Designer.csの差分
Form1.Designer.csには、イベントの関連付けが1行だけ追加される
button1.Click += button1_Click;

これは、

button1のClickイベントが発生したら、button1_Clickを呼び出す

という関連付けです。

Form1.csの変更

一方、Form1.csには実際に実行する処理が追加されています。

Clickイベント追加時のForm1.csの差分
Form1.csには、クリックされたときに実行するメソッドが追加される
private void button1_Click(object sender, EventArgs e)
{
    label1.Text = "ボタンを押した";
}

この2つをつなげて考えると、WinFormsのイベント処理が見えてきます。

ユーザーがButtonをクリック
        ↓
Clickイベントが発生
        ↓
button1.Click += button1_Click
        ↓
button1_Click() が呼び出される
        ↓
label1.Text が変更される
        ↓
Labelの表示が「ボタンを押した」に変わる

これがWinFormsの基本的なイベント駆動プログラミングです。

Designer.csとForm1.csは何が違う?

今回のGitHub Desktopの差分を見ると、2つのファイルの役割も分かりやすくなります。

ファイル主な役割
Form1.Designer.csコントロールの生成、プロパティ設定、配置、イベントの関連付けなど
Form1.csボタンが押されたときなど、自分で実行したい処理を書く

Form1.Designer.csは、基本的にVisual Studioのデザイナーが管理するファイルです。

そのため、通常はDesigner.csを直接書き換えるのではなく、デザイナーやプロパティウィンドウを使って編集します

一方、Form1.csには、自分が実現したい処理を書いていきます。

GitHub Desktopを使うと「自動生成」が見える

Visual Studioだけを使っていると、

Buttonを置いた
Labelを置いた
Buttonをダブルクリックした

だけに見えます。

しかし、そのたびにコミットしてGitHub Desktopで差分を見ると、

Visual Studioで操作する
        ↓
ソースコードが変更される
        ↓
GitHub Desktopで差分を見る
        ↓
「何がコードになったのか」が分かる

という学習ができます。

特に初心者のうちは、デザイナーを「画面を作るための特別な仕組み」と考えてしまいがちです。

実際には、その裏側では、

button1 = new Button();

のようにオブジェクトを生成し、

button1.Text = "button1";

のようにプロパティを設定し、

Controls.Add(button1);

のようにオブジェクト同士を組み合わせています。

つまり、これまで学習してきたクラス、オブジェクト、プロパティ、メソッド、イベントが、そのままWinFormsの画面作成にも使われているのです。

Gitの理解にもつながる

この実験はWinFormsだけでなく、Gitを理解するためにも役立ちます。

たとえば、

  1. 空のFormをコミットする
  2. Buttonを置いて差分を見る → コミット
  3. Labelを置いて差分を見る → コミット
  4. Clickイベントを作って差分を見る → コミット

と進めれば、1回の操作によって、どのファイルのどのコードが変化したのかを段階的に確認できます。

Clickイベントの追加では、

Form1.Designer.cs
Form1.cs

という2つのファイルが同時に変更されました。

ここから、

「私はButtonをダブルクリックして処理を書いただけなのに、なぜ2つのファイルが変更されたのだろう?」

と考えてみるのもよいでしょう。

Gitの差分は、単に「変更を確認するためのもの」ではありません。

プログラムがどのように作られているのかを調べる道具としても使えるのです。

まとめ

今回の実験で確認できたことを整理すると、次のようになります。

Visual Studioで行ったことGitHub Desktopで確認できた主な変更
Buttonを配置new Button()、プロパティ設定、Controls.Add(button1)など
Labelを配置new Label()、プロパティ設定、Controls.Add(label1)など
Clickイベントを追加Form1.Designer.csbutton1.Click += button1_Click
Click時の処理を書くForm1.csbutton1_Click()が追加

デザイナーでButtonを1個置くという簡単な操作でも、その裏ではC#のコードが生成されています。

そしてGitHub Desktopで差分を見ると、その「裏側」を簡単に観察できます。

デザイナーで操作する → GitHub Desktopで差分を見る。

この習慣をつけると、「画面上では何となく動いた」で終わらず、C#のコードとして何が起きているのかを理解しながらWinFormsを学べるようになります。

次のステップ:今度は自分でインスタンスを作ってみよう

今回は、Visual Studioのデザイナーがnew Button()などのコードを自動生成していることを確認しました。

では、デザイナーを使わずに、自分でnew Button()と書いたらどうなるのでしょうか。次の記事では、実行中にButtonのインスタンスを作るところから、クラスとインスタンス、そしてオブジェクト指向の入り口へとつなげていきます。

WinFormsで学ぶインスタンス ― Designerが書いたコードを自分で書いてみよう

同じテーマを短い記事に分けて解説した、WinFormsの「ドラッグ&ドロップ」の正体(シリーズ目次)もあります。

訪問数 26 回, 今日の訪問数 26回

広告