【C#入門】ButtonとUserControlで学ぶ継承|独自プロパティを表示しよう

2026年9月1日

広告

Windows Formsのコントロールは、すべてクラスから作られています。たとえば、画面に配置するButtonはButtonクラス、複数の部品をまとめるUserControlはUserControlクラスがもとになっています。

この記事では、最初にButtonを継承して小さな自作コントロールを作り、次にUserControlを継承して複数の部品をまとめるところまで進みます。自作プロパティをVisual Studioのプロパティウィンドウへ表示する方法も確認します。

この記事で学ぶこと

  • class 子クラス : 親クラスという継承の書き方
  • 親クラスの機能を受け継ぎ、新しい機能を追加する考え方
  • 自作コントロールをツールボックスからフォームへ配置する方法
  • 自作プロパティをプロパティウィンドウへ表示する方法
  • Buttonの継承とUserControlの使い分け

準備:プロジェクトを作成する

  1. Visual Studioを起動します。
  2. 「新しいプロジェクトの作成」を選びます。
  3. 「Windows フォーム アプリ」を選択します。
  4. プロジェクト名をWinFormsInheritanceSampleにします。
  5. ソリューション名もWinFormsInheritanceSampleにそろえます。
  6. フレームワークは.NET 10.0(長期サポート版)を選びます。

選ぶのは「Windows フォーム アプリ」です。名前の似ている「Windows フォーム アプリケーション(.NET Framework)」ではないので注意してください。

Visual Studioの新しいプロジェクト作成画面でWindows フォーム アプリを選択しているところ
「Windows フォーム アプリ」を選択します。「.NET Framework」と書かれたテンプレートと間違えないように注意しましょう。

この記事では、プロジェクト名とソリューション名を、どちらもWinFormsInheritanceSampleにします。同じ名前で作成すると、この記事の画面やコードと見比べながら進めやすくなります。

第1段階:Buttonを継承してみよう

継承の最初の練習にはButtonが向いています。Buttonはすでに「文字を表示する」「クリックできる」「背景色を変える」といった機能を持っています。その機能を受け継ぎながら、ゲーム用のDamageプロパティを追加してみましょう。

標準のButtonを継承し、Damageプロパティを持つDamageButtonを作るイメージ
Buttonの機能を受け継ぎ、Damageプロパティを追加します

DamageButtonクラスを追加する

ソリューション エクスプローラーでプロジェクトを右クリックし、「追加」→「クラス」を選びます。ファイル名はDamageButton.csにします。

作成直後は、internal class DamageButtonと表示されます。これはVisual Studio 2026が自動生成する正常なコードです。ここからinternalpublicへ変更し、クラス名の後ろへ: Buttonを追加します。ファイルの内容を次のコードに書き換えてください。

using System.ComponentModel;

namespace WinFormsInheritanceSample
{
    public class DamageButton : Button
    {
        [Category("ゲーム設定")]
        [Description("ボタンを押したときに与えるダメージです")]
        [DefaultValue(10)]
        public int Damage { get; set; } = 10;
    }
}

重要なのは次の1行です。

public class DamageButton : Button

publicにすると、Visual Studioのデザイナーやツールボックスからこのクラスを利用できます。: Buttonは、Buttonを継承するという指定です。

DamageButtonが子クラス、Buttonが親クラスです。DamageButtonには自分で一からクリック機能を書いていません。それでもクリックできるのは、Buttonの機能を受け継いでいるからです。

Visual Studioのオブジェクト ブラウザーでButtonの継承関係を確認する画面
Visual Studioのオブジェクト ブラウザーでも、Buttonの継承関係を確認できます

ビルドしてツールボックスに表示する

  1. メニューの「ビルド」→「ソリューションのビルド」を選びます。
  2. Form1.cs[デザイン]を開きます。
  3. ツールボックス内を確認します。見つからない場合は、検索欄にDamageButtonと入力します。
  4. DamageButtonをフォームへドラッグ&ドロップします。
  5. 配置したDamageButtonを選択し、プロパティウィンドウでTextを「攻撃」、BackColorを「OrangeRed」、ForeColorを「White」に設定します。

表示されないときは、まずビルドエラーがないか確認してください。ツールボックスを右クリックして「ツールボックスのリセット」を行う前に、プロジェクトを保存してもう一度ビルドするのが基本です。

プロパティウィンドウを確認する

フォームに配置したDamageButtonを選択し、プロパティウィンドウを開きます。継承したTextBackColorForeColorは、標準のButtonと同じように設定できます。また、「ゲーム設定」という分類の中に独自プロパティのDamageが表示されます。値を10から30などに変更できます。

属性役割
Category("ゲーム設定")プロパティを表示する分類名を決める
Description("...")選択したときに説明文を表示する
DefaultValue(10)設計時の既定値をVisual Studioへ伝える

注意:DefaultValue(10)は、実際に10を代入する命令ではありません。そのため、プロパティ側でも= 10;と初期値を設定しています。

Damageを使ってみる

フォーム上のDamageButtonをダブルクリックし、Clickイベントに次のコードを書きます。コントロール名がdamageButton1になっていることを確認してください。

private void damageButton1_Click(object sender, EventArgs e)
{
    MessageBox.Show(damageButton1.Damage + "ダメージ!");
}

プロパティウィンドウでDamageを30に変更して実行すると、「30ダメージ!」と表示されます。コードを書き換えなくても、設計画面から値を変更できました。

第2段階:UserControlを継承してみよう

Buttonの継承では、1つのボタンにプロパティや動作を追加できました。しかし、「名前」「体力の数値」「体力バー」を1つの部品として扱いたい場合は、複数のコントロールをまとめられるUserControlが適しています。

LabelとProgressBarをまとめてCharacterStatusControlとして再利用するUserControlのイメージ
LabelやProgressBarをまとめ、1つのUserControlとして再利用できます

UserControlを追加する

  1. プロジェクトを右クリックします。
  2. 「追加」→「ユーザー コントロール」を選びます。
  3. 名前をCharacterStatusControl.csにします。
  4. デザイン画面にLabelを2個、ProgressBarを1個配置します。
  5. 名前をそれぞれnameLabelhealthLabelhealthBarにします。

生成されたコードを見ると、クラス宣言は次のようになっています。

public partial class CharacterStatusControl : UserControl

これも継承です。Visual Studioが: UserControlを書いてくれているため、普段は意識しにくいだけです。

外から変更できるプロパティを追加する

CharacterStatusControl.csを開き、次のようにします。デザイナーが管理するCharacterStatusControl.Designer.csではなく、通常のCharacterStatusControl.csへ書いてください。

using System.ComponentModel;

namespace WinFormsInheritanceSample
{
    public partial class CharacterStatusControl : UserControl
    {
        private int _health = 100;

        public CharacterStatusControl()
        {
            InitializeComponent();

            nameLabel.Text = "勇者";
            healthBar.Minimum = 0;
            healthBar.Maximum = 100;
            UpdateDisplay();
        }

        [Category("キャラクター設定")]
        [Description("画面に表示するキャラクター名です")]
        [DefaultValue("勇者")]
        public string CharacterName
        {
            get => nameLabel.Text;
            set => nameLabel.Text = value;
        }

        [Category("キャラクター設定")]
        [Description("0から100までの体力です")]
        [DefaultValue(100)]
        public int Health
        {
            get => _health;
            set
            {
                _health = Math.Clamp(value, 0, 100);
                UpdateDisplay();
            }
        }

        private void UpdateDisplay()
        {
            healthBar.Value = _health;
            healthLabel.Text = _health + " / 100";
        }
    }
}

Math.Clamp(value, 0, 100)は、入力された値を0から100の範囲に収める処理です。たとえば120を設定しても100になり、マイナスの値を設定しても0になります。

ビルド後、CharacterStatusControlをForm1へ配置します。プロパティウィンドウの「キャラクター設定」にCharacterNameHealthが表示されます。値を変更すると、UserControl内部のLabelとProgressBarにも反映されます。

CharacterStatusControlをForm1で使ってみよう

作成したCharacterStatusControlを、実際にForm1で使ってみましょう。

  1. メニューの「ビルド」→「ソリューションのビルド」を選びます。
  2. Form1.cs[デザイン]を開きます。
  3. ツールボックスでCharacterStatusControlを探します。見つからない場合は検索欄へ名前を入力します。
  4. CharacterStatusControlをForm1へドラッグ&ドロップします。
  5. 配置したCharacterStatusControlを選択します。
  6. プロパティウィンドウの「キャラクター設定」で、CharacterNameを「勇者」、Healthを「80」に変更します。

実行すると、CharacterStatusControlに「勇者」と「80 / 100」が表示され、ProgressBarも80に変わります。

コードからプロパティを変更する

プロパティウィンドウだけでなく、Form1のコードからも値を変更できます。Form1のコンストラクターを次のようにします。

public Form1()
{
    InitializeComponent();

    characterStatusControl1.CharacterName = "勇者";
    characterStatusControl1.Health = 80;
}

characterStatusControl1は、Form1へ配置したUserControlの名前です。名前が異なる場合は、プロパティウィンドウの(Name)を確認してください。

DamageButtonと組み合わせる

次に、DamageButtonを押すとキャラクターの体力が減るようにします。Form1に配置したDamageButtonをダブルクリックし、Clickイベントを次のように書き換えます。

private void damageButton1_Click(object sender, EventArgs e)
{
    characterStatusControl1.Health -= damageButton1.Damage;
}

Damageが10なら、ボタンを押すたびにHealthが10ずつ減ります。Healthプロパティの中で表示更新も行っているため、数値とProgressBarが一緒に変化します。0より小さくならないのは、Math.Clampで範囲を0から100に制限しているためです。

この例では、DamageButtonが「ダメージ量」、CharacterStatusControlが「キャラクターの状態」を担当し、Form1が2つの部品を組み合わせています。

ButtonとUserControlはどう使い分ける?

作りたいもの向いている方法理由
特別な見た目や設定を持つボタンButtonを継承Buttonの機能をそのまま利用できる
数字しか入力できない入力欄TextBoxなどを継承1つの既存コントロールを拡張できる
名前・画像・体力バーのセットUserControlを継承複数のコントロールを1つにまとめられる
何度も使う入力フォームのまとまりUserControlを継承部品として再利用しやすい

覚え方はシンプルです。

  • 1つの既存コントロールを強化する → Buttonなどを継承
  • 複数のコントロールを1つにまとめる → UserControlを継承

継承で何が起きているのか

DamageButtonはButtonの機能を受け継ぎ、その上にDamageを追加しました。CharacterStatusControlはUserControlの機能を受け継ぎ、その中にLabelやProgressBarを組み合わせました。

Control
 ├─ Button
 │   └─ DamageButton
 └─ UserControl
     └─ CharacterStatusControl

自作クラスも、さらに別のクラスから継承できます。ただし、継承を何段も重ねると関係が分かりにくくなるため、最初は「既存のコントロールを1回継承する」練習から始めましょう。

よくあるつまずき

ツールボックスに表示されない

クラスを追加しただけでは表示されないことがあります。ソリューションをビルドし、エラーが0件であることを確認してください。

プロパティウィンドウに独自プロパティがない

クラスやプロパティがpublicになっているか、プロパティにgetsetがあるかを確認します。コードを直したあとは再度ビルドしてください。

デザイナーが開けなくなった

InitializeComponent()を削除していないか確認してください。また、通常は*.Designer.csを直接編集しません。自分の処理は通常のクラスファイルへ書きます。

練習課題

  1. DamageButtonにAttackNameプロパティを追加し、プロパティウィンドウから「炎攻撃」などを設定してみましょう。
  2. DamageButtonの背景色をプロパティウィンドウから変えてみましょう。
  3. CharacterStatusControlにMaxHealthプロパティを追加してみましょう。
  4. Healthが30以下になったら、healthLabelの文字色を赤にしてみましょう。

まずは自分で取り組み、分からないときや自分のコードと比較したいときに「サンプル解答を見る」を開いてください。プログラムには複数の実現方法があるため、ここで紹介するコードは解答例の1つです。

問題1のサンプル解答を見る:AttackNameプロパティ

Buttonから受け継いだTextプロパティを、AttackNameから読み書きできるようにします。DamageButtonクラスへ次のプロパティを追加します。

[Category("ゲーム設定")]
[Description("ボタンに表示する攻撃名です")]
[DefaultValue("攻撃")]
public string AttackName
{
    get => Text;
    set => Text = value;
}

ビルドすると、プロパティウィンドウの「ゲーム設定」にAttackNameが表示されます。「炎攻撃」と入力すると、ボタンに表示される文字も変わります。

問題2のサンプル解答を見る:背景色の変更

フォームに配置したDamageButtonを選択し、プロパティウィンドウのBackColorを好きな色へ変更します。たとえば青色にする場合は「DodgerBlue」を選びます。

実行すると、選択したDamageButtonの背景色が変わります。コードを書き換えず、フォームごとに別の色を設定できます。

問題3のサンプル解答を見る:MaxHealthプロパティ

MaxHealthを追加する場合は、プロパティを1つ増やすだけでなく、Healthの上限、ProgressBarのMaximum、体力の表示も変更します。

まず、最大体力を保存するフィールドとMaxHealthプロパティを追加します。

private int _maxHealth = 100;

[Category("キャラクター設定")]
[Description("キャラクターの最大体力です")]
[DefaultValue(100)]
public int MaxHealth
{
    get => _maxHealth;
    set
    {
        _maxHealth = Math.Max(1, value);
        _health = Math.Min(_health, _maxHealth);
        UpdateDisplay();
    }
}

次に、Healthプロパティの上限を100から_maxHealthへ変更します。

_health = Math.Clamp(value, 0, _maxHealth);

最後に、UpdateDisplayメソッドを次のように変更します。コンストラクターにあるhealthBar.Maximum = 100;は削除して構いません。

private void UpdateDisplay()
{
    healthBar.Maximum = _maxHealth;
    healthBar.Value = _health;
    healthLabel.Text = _health + " / " + _maxHealth;
}

これで、MaxHealthを200に設定すると「現在の体力 / 200」と表示され、ProgressBarの最大値も200になります。

問題4のサンプル解答を見る:体力が少ないときに赤くする

UpdateDisplayメソッドの最後へ、次のif文を追加します。

if (_health <= 30)
{
    healthLabel.ForeColor = Color.Red;
}
else
{
    healthLabel.ForeColor = SystemColors.ControlText;
}

体力が30以下になると文字が赤くなり、31以上へ戻ると通常の文字色へ戻ります。elseを書かないと、一度赤くなった文字が元の色へ戻らない点に注意しましょう。

まとめ

  • 継承はclass 子クラス : 親クラスと書く
  • 子クラスは親クラスの機能を受け継げる
  • Buttonの継承は「1つのコントロールを強化する」練習に向いている
  • UserControlの継承は「複数のコントロールを1つにまとめる」ときに向いている
  • 属性を付けると独自プロパティをプロパティウィンドウで分かりやすく扱える

Buttonで小さな継承を体験してからUserControlへ進むと、「受け継ぐ」と「組み合わせる」の違いが見えやすくなります。継承を文法だけで覚えず、Visual Studioのデザイナー上で動く部品として確かめてみてください。

訪問数 394 回, 今日の訪問数 1回

広告