WinForms + JSON 書籍管理アプリ 初学者向けチュートリアル
目次
1. ゴール
- 書籍の「タイトル」「著者」「価格」を登録できる
- 登録データが一覧(表)に表示される
- 選択行を削除できる
- アプリ終了時に自動で JSON 保存
- アプリ起動時に JSON から自動で読み込み
2. 準備
必要な環境
- Visual Studio 2022
- ワークロード:.NET デスクトップ開発
- .NET 8 SDK(インストール済みなら VS で選べます)
3. 新しいプロジェクト作成
- Visual Studio を起動 → 「新しいプロジェクトの作成」
- 「Windows フォーム アプリ」(.NET 6/7/8 用) を選択
- プロジェクト名:BookManager
- フレームワーク:.NET 8.0
- 作成をクリック
4. UI の設計(デザイナ)
コントロールの配置
フォーム (Form1) に以下を配置します。
コントロール | Name プロパティ | Text(表示名) | 備考 |
---|---|---|---|
DataGridView | bookDataGrid | (空) | 列は後で自動生成 |
Label | – | 書名 | |
TextBox | txtTitle | (空) | |
Label | – | 著者 | |
TextBox | txtAuthor | (空) | |
Label | – | 価格 | |
TextBox | txtPrice | (空) | |
Button | btnAdd | 登録 | |
Button | btnRemove | 削除 |
5. コードの作成
5.1 書籍データクラス(BookRecord.cs)
プロジェクトに「クラス」を追加し、以下を記述します。
public class BookRecord
{
public string Title { get; set; } = "";
public string Author { get; set; } = "";
public int Price { get; set; }
}
5.2 Form1.cs のコード
既存のコードを以下に置き換えます。
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.Unicode;
using System.Windows.Forms;
namespace BookManager
{
public partial class Form1 : Form
{
private BindingSource bindingSource = new BindingSource();
private List<BookRecord> books = new List<BookRecord>();
public Form1()
{
InitializeComponent();
// DataGridView とデータを結びつける
bindingSource.DataSource = books;
bookDataGrid.DataSource = bindingSource;
// 列名の表示をわかりやすく
bookDataGrid.AutoGenerateColumns = true;
}
// 起動時に JSON 読み込み
private void Form1_Load(object sender, EventArgs e)
{
LoadDataFromJson();
}
// 終了時に JSON 保存
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
SaveDataAsJson();
}
// 登録ボタン
private void btnAdd_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtTitle.Text) ||
string.IsNullOrWhiteSpace(txtAuthor.Text))
{
MessageBox.Show("書名と著者は必須です。", "入力エラー",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (!int.TryParse(txtPrice.Text, out int price) || price < 0)
{
MessageBox.Show("価格は0以上の整数を入力してください。", "入力エラー",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
books.Add(new BookRecord
{
Title = txtTitle.Text.Trim(),
Author = txtAuthor.Text.Trim(),
Price = price
});
bindingSource.ResetBindings(false);
txtTitle.Clear();
txtAuthor.Clear();
txtPrice.Clear();
txtTitle.Focus();
}
// 削除ボタン
private void btnRemove_Click(object sender, EventArgs e)
{
if (bookDataGrid.CurrentRow == null)
{
MessageBox.Show("削除する行を選択してください。", "削除",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
int index = bookDataGrid.CurrentRow.Index;
if (index >= 0 && index < books.Count)
{
books.RemoveAt(index);
bindingSource.ResetBindings(false);
}
}
// JSON保存先
private string GetJsonPath()
{
string baseDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"BookManager");
if (!Directory.Exists(baseDir))
Directory.CreateDirectory(baseDir);
return Path.Combine(baseDir, "BookData.json");
}
// JSONに保存
private void SaveDataAsJson()
{
try
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
};
var json = JsonSerializer.Serialize(books, options);
File.WriteAllText(GetJsonPath(), json, Encoding.UTF8);
}
catch (Exception ex)
{
MessageBox.Show("保存に失敗しました。\n" + ex.Message, "保存エラー",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// JSONから読み込み
private void LoadDataFromJson()
{
try
{
string path = GetJsonPath();
if (File.Exists(path))
{
var json = File.ReadAllText(path, Encoding.UTF8);
books = JsonSerializer.Deserialize<List<BookRecord>>(json) ?? new();
bindingSource.DataSource = books;
bindingSource.ResetBindings(false);
}
}
catch (Exception ex)
{
MessageBox.Show("読み込みに失敗しました。\n" + ex.Message, "読み込みエラー",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
6. イベント配線
デザイナで Form を選択し、プロパティ(稲妻マーク)で以下を設定:
- Load → Form1_Load
- FormClosing → Form1_FormClosing
ボタン:
- btnAdd.Click → btnAdd_Click
- btnRemove.Click → btnRemove_Click
7. 実行と確認
- F5 で実行
- 「書名」「著者」「価格」を入力して 登録
- 登録内容が一覧に表示される
- アプリを終了 → 再起動するとデータが残っている
8. 発展課題
- 検索機能(タイトルや著者で絞り込み)
- ソート(価格やタイトル順)
- 別フォルダやファイル名を選べる保存機能
- JSONのバックアップ作成
訪問数 1 回, 今日の訪問数 1回
ディスカッション
コメント一覧
まだ、コメントがありません