2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Visual C# と MySQL の勉強で簡易的な TODO リストを作って勉強してみた

Last updated at Posted at 2024-11-05

C# と MySQL で簡易的な TODO リストを作成しました。
最近 C# を勉強し始めたばかりなので、内容に不備などあるかもしれませんがご了承ください。

バージョン

  • MySQL 9.0.1
  • Visual Studio 2022
  • C# 12.0
  • .NET 8.0.10

MySQL の準備

勉強用でちょっと動かすだけなので docker で簡単に用意する。

docker-compose.yml
version: "3"

services:
  db:
    image: mysql
    container_name: mysql
    environment:
      # 設定必須、rootパスワード
      - MYSQL_ROOT_PASSWORD=root
      # この設定はオプション、イメージの起動時に作成されるデータベース名
      - MYSQL_DATABASE=sample
    ports:
      - 3306:3306
    volumes:
      - mysql_data:/var/lib/mysql
  phpmyadmin:
      container_name: phpmyadmin
      image: phpmyadmin/phpmyadmin
      environment:
          - PMA_ARBITRARY=1
          - PMA_HOST=mysql
          - PMA_USER=root
          - PMA_PASSWORD=root
      ports:
          - 8080:80
      depends_on:
          - db

volumes:
  mysql_data:

docker-compose.yml があるフォルダで docker-compose up を実行すると、

http://localhost:8080/ で phpmyadmin から MySQL に接続できているので、データベース sample にテーブルを作成する。

CREATE TABLE `sample`.`todos` (
  `id` int NOT NULL AUTO_INCREMENT,
  `todo` text NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
);

img01.png

Visual Studio でプロジェクト作成

img02.png

img03.png

Visual Studio の画面から DataGridView を配置する。

img05.png


MySql.Data を NuGet パッケージ管理から入れる。

MySql.Data をラップして少し使いやすくしたクラスを作成する。

Db.cs
using MySql.Data.MySqlClient;

namespace TodoList
{
    internal class Db
    {
        private static MySqlConnection? _connection;

        private static MySqlConnection GetConnection()
        {
            if (_connection == null)
            {
                _connection = new MySqlConnection("server=127.0.0.1;uid=root;pwd=root;database=sample");
                _connection.Open();
            }
            return _connection;
        }

        public static void Execute(string sql, object?[]? param = null)
        {
            var command = new MySqlCommand(sql, GetConnection());
            Array.ForEach(param ?? [], p => command.Parameters.Add(new MySqlParameter("", p)));
            command.ExecuteNonQuery();
        }

        public static string[][] ExecuteAndFetchAll(string sql, object?[]? param = null)
        {
            var lines = new List<string[]>();

            var command = new MySqlCommand(sql, GetConnection());
            Array.ForEach(param ?? [], p => command.Parameters.Add(new MySqlParameter("", p)));
            using var reader = command.ExecuteReader();
            while (reader.Read())
            {
                string[] line = new string[reader.FieldCount];
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    line[i] = reader.GetValue(i)?.ToString() ?? "";
                }
                lines.Add(line);
            }

            return lines.ToArray();
        }
    }
}

Form1 のコードで Todo リストを作る。

Form1.cs
using System.Data;

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

            InitGrid();
        }

        private void InitGrid()
        {
            dataGridView1.DataSource = makeGridView();

            // 変更できないカラムを設定する
            foreach (int key in new List<int> { 0, 2, 3 })
            {
                dataGridView1.Columns[key].ReadOnly = true;
                dataGridView1.Columns[key].DefaultCellStyle.BackColor = Color.LightGray;
            }

            // "更新する"ボタンの列を追加
            var updeatColumn = new DataGridViewButtonColumn();
            updeatColumn.Name = "更新";
            updeatColumn.UseColumnTextForButtonValue = true;
            updeatColumn.Text = "更新する";
            dataGridView1.Columns.Add(updeatColumn);

            // "削除する"ボタンの列を追加
            var delColumn = new DataGridViewButtonColumn();
            delColumn.Name = "削除";
            delColumn.UseColumnTextForButtonValue = true;
            delColumn.Text = "削除する";
            dataGridView1.Columns.Add(delColumn);

            // データがない一番下の行にも"更新する"ボタンを表示する
            Action drawBtnText = () => dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells["更新"].Value = "更新する";
            dataGridView1.RowsAdded += (object? sender, DataGridViewRowsAddedEventArgs e) => drawBtnText();

            // データ更新イベント設定
            dataGridView1.CellContentClick += upsert;
            dataGridView1.CellContentClick += delete;
        }

        private DataTable makeGridView()
        {
            var dataTable = new DataTable();

            dataTable.TableName = "Todos";

            dataTable.Columns.Add("id");
            dataTable.Columns.Add("内容");
            dataTable.Columns.Add("作成日");
            dataTable.Columns.Add("更新日");

            var todos = Db.ExecuteAndFetchAll("SELECT * FROM todos");
            foreach (string[] row in todos)
            {
                dataTable.Rows.Add(row);
            }
            return dataTable;
        }

        private void upsert(object? sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != dataGridView1.Columns["更新"].Index || e.RowIndex == -1)
            {
                // 更新ボタンを押してない場合は何もしない
                return;
            }

            var isNewRow = false;
            if (!int.TryParse(dataGridView1.Rows[e.RowIndex].Cells["id"].Value?.ToString(), out var id))
            {
                // id が取得できない場合は新規レコード作成する
                isNewRow = true;
            }

            var todoTxt = dataGridView1.Rows[e.RowIndex].Cells["内容"].Value?.ToString();
            if (string.IsNullOrEmpty(todoTxt))
            {
                MessageBox.Show("内容を設定してください");
                return;
            }


            if (isNewRow == true)
            {
                Db.Execute("INSERT INTO todos (todo, created_at, updated_at) VALUES (?, ?, ?)", [todoTxt, DateTime.Now, DateTime.Now]);
            }
            else
            {
                Db.Execute("UPDATE todos SET todo = ?, updated_at = ? WHERE id = ?", [todoTxt, DateTime.Now, id]);
            }

            dataGridView1.DataSource = makeGridView();
        }

        private void delete(object? sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != dataGridView1.Columns["削除"].Index || e.RowIndex == -1)
            {
                // 削除ボタンを押してない場合は何もしない
                return;
            }

            if (!int.TryParse(dataGridView1.Rows[e.RowIndex].Cells["id"].Value?.ToString(), out var id))
            {
                MessageBox.Show("id が取得できません");
                return;
            }

            Db.Execute("DELETE FROM todos WHERE id = ?", [id]);

            dataGridView1.DataSource = makeGridView();
        }
    }
}

簡単に Todo リストを作成できました。

img06.png


参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?