【入門】WinForms × DataSet で作る「書籍管理アプリ」

〜保存・ロード機能を実装しよう〜


1. はじめに

「本のタイトルと著者、価格を入力して一覧化 → 保存 → 次回起動時に復元」

こんなシンプルなアプリを WinForms + DataSet で作ってみます。

この記事は 初心者向けで、以下の機能にしぼっています:

  • DataGridView にデータを入力
  • 保存ボタンでXMLに保存
  • 起動時に自動で読み込み

短いコードで動作するので、C#とWinFormsの学習に最適です。


2. プロジェクトの作成

  1. Visual Studio を起動
  2. 「新しいプロジェクトの作成」を選択
  3. プロジェクトテンプレートから
    • C# → Windows フォーム アプリ (.NET Framework) を選択
    • プロジェクト名は BookManager にします

3. 画面デザイン(UI)

フォームに以下のコントロールを配置します。

  • DataGridView : 書籍一覧 (bookDataGrid)
  • TextBox : 書名 (bookName)、著者 (author)、価格 (price)
  • Button : 「登録」(addButton)、 「削除」(removeButton)

配置例(イメージ):

DataGridView が上にあり、その下に「書名」「著者」「値段」の TextBox と「登録」「削除」ボタンを配置。


4. データセットの準備

  1. ソリューションエクスプローラーでプロジェクトを右クリック
  2. 「追加」→「新しい項目」
  1. 「データセット」を選び、名前を bookDataSet.xsd にします

次に DataSet デザイナが開きます。ここで「DataTable」を追加し、列を定義します。

  • 列1: Title(string型)
  • 列2: Author(string型)
  • 列3: Price(int型)

DataSet デザイナ画面に DataTable を追加し、列「Title」「Author」「Price」を定義している画面。


5. コードの追加

Form1.cs に以下のコードを追加します。

using System;
using System.Data;
using System.IO;
using System.Windows.Forms;

namespace BookManager
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 起動時にデータを読み込む
        private void Form1_Load(object sender, EventArgs e)
        {
            LoadData();
        }

        // 終了時にデータを保存
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveData();
        }

        // 登録ボタン
        private void AddButtonClicked(object sender, EventArgs e)
        {
            bookDataSet.bookDataTable.AddbookDataTableRow(
                bookName.Text,
                author.Text,
                int.Parse(price.Text));

            bookName.Clear();
            author.Clear();
            price.Clear();
        }

        // 削除ボタン
        private void RemoveButtonClicked(object sender, EventArgs e)
        {
            if (bookDataGrid.CurrentRow != null)
            {
                bookDataGrid.Rows.RemoveAt(bookDataGrid.CurrentRow.Index);
            }
        }

        // 保存処理
        private void SaveData(bool showMessage = false)
        {
            try
            {
                string path = GetDataFilePath();
                bookDataSet.WriteXml(path, XmlWriteMode.WriteSchema);
                if (showMessage) MessageBox.Show("保存しました。");
            }
            catch (Exception ex)
            {
                MessageBox.Show("保存に失敗しました: " + ex.Message);
            }
        }

        // 読み込み処理
        private void LoadData(bool showMessage = false)
        {
            try
            {
                string path = GetDataFilePath();
                bookDataSet.bookDataTable.Clear();

                if (File.Exists(path))
                {
                    bookDataSet.ReadXml(path, XmlReadMode.ReadSchema);
                    if (showMessage) MessageBox.Show("読み込みました。");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("読み込みに失敗しました: " + ex.Message);
            }
        }

        // 保存ファイルの場所(ユーザーごとのAppData)
        private string GetDataFilePath()
        {
            string dir = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "BookManager");
            Directory.CreateDirectory(dir);
            return Path.Combine(dir, "BookData.xml");
        }
    }
}

方法① デザイナから登録(初心者向け)

  1. フォームデザイナを開く
  2. フォームをクリックして選択
  3. プロパティウィンドウの「イベント」タブ(⚡マーク)を選択
  4. Load の欄に Form1_Load と入力
  5. FormClosing の欄に Form1_FormClosing と入力

これで自動的に InitializeComponent(); の中に以下のコードが追加されます:

this.Load += new System.EventHandler(this.Form1_Load);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);

方法② コードから手動登録(上級者向け)

Form1.cs のコンストラクタに以下を追加します。

public Form1()
{
    InitializeComponent();

    // イベントハンドラをコードで登録
    this.Load += Form1_Load;
    this.FormClosing += Form1_FormClosing;
}

こちらの方が イベントがどこで紐づいているかが見やすい というメリットがあります。


初学者向けまとめ

  • Form1_Load は「起動時に処理を実行したい」場所
  • Form1_FormClosing は「終了時に処理を実行したい」場所
  • Visual Studio では「デザイナから登録」しておけば自動で結びつくので、まずはそちらがおすすめ
  • 慣れてきたら「コードで登録」する方法も覚えると良い

処理の流れ

1.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)

  • Windows が用意している 「ユーザーごとのアプリデータ保存場所」 のパスを取得します。
  • 例:
    • Windows 10/11 の場合C:\Users\ユーザー名\AppData\Local

ここを使うことで、「誰が使っても、その人専用の保存先」にデータを置けます。

(プログラムをインストールしたフォルダに直接保存すると、権限の問題でエラーになりやすいのでNGです)


2. Path.Combine(…, “BookManager")

  • 上で取った AppData\Local に “BookManager” フォルダ をくっつけています。
  • 結果の例:C:\Users\ユーザー名\AppData\Local\BookManager

→ プロジェクト名と同じ名前のフォルダを作って、その中に保存するようにしています。


3. Directory.CreateDirectory(dir)

  • 指定したフォルダがなければ 自動で作成 します。
  • すでに存在していれば何もしません。
  • これで「初回起動時にフォルダがなくてエラーになる」という問題を防いでいます。

4. return Path.Combine(dir, “BookData.xml");

  • 最後に、BookManager フォルダの中に BookData.xml というファイル名を付けて返します。
  • 例:C:\Users\ユーザー名\AppData\Local\BookManager\BookData.xml

これが「保存/読み込み」に使われるファイルのフルパスです。


ポイントまとめ

  • ユーザーごとの専用領域に保存する → 権限の問題を避けられる
  • プロジェクト用のフォルダを作成する → 他アプリとファイルが混ざらない
  • パスを組み立てる処理を関数にまとめている → 保存/読み込み両方で使い回せる

例:実際の保存先パス

ユーザー名が taro の場合:

C:\Users\taro\AppData\Local\BookManager\BookData.xml

つまりこのメソッドは「環境依存しない、安全な保存先のパスを作って返す」ための便利関数です。



6. 実行してみよう

  1. プログラムを起動すると、空の DataGridView が表示されます
  2. テキストボックスに「書名・著者・価格」を入力して [登録] をクリック→ DataGridView に行が追加されます
  1. アプリを終了すると、ローカルの AppData に BookData.xml が保存されます

メモ帳で BookData.xml を開いた画面(XMLの中身が見える):

<?xml version="1.0" standalone="yes"?>
<BookDataSet xmlns="http://tempuri.org/BookDataSet.xsd">
  <xs:schema id="BookDataSet" targetNamespace="http://tempuri.org/BookDataSet.xsd"
             xmlns:mstns="http://tempuri.org/BookDataSet.xsd"
             xmlns="http://tempuri.org/BookDataSet.xsd"
             xmlns:xs="http://www.w3.org/2001/XMLSchema"
             xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
             attributeFormDefault="qualified" elementFormDefault="qualified">

    <!-- スキーマ定義(テーブルの列構造) -->
    <xs:element name="BookDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
      <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
          <xs:element name="bookDataTable">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="書名" type="xs:string" minOccurs="0" />
                <xs:element name="著者" type="xs:string" minOccurs="0" />
                <xs:element name="値段" type="xs:int" minOccurs="0" />
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:choice>
      </xs:complexType>
    </xs:element>
  </xs:schema>

  <!-- 実データ部分 -->
  <bookDataTable>
    <書名>吾輩は猫である</書名>
    <著者>夏目漱石</著者>
    <値段>1200</値段>
  </bookDataTable>
</BookDataSet>
  1. 再起動すると前回のデータが復元されます

7. まとめ

  • DataSet + DataGridView で簡単に表形式データを管理できる
  • 保存/ロードは WriteXml / ReadXml だけで実装可能
  • 保存先は XML なので、中身を直接確認できる

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

C#,XML,データベース

Posted by hidepon