C# DataGridViewにDataTableを表示・更新する方法|初心者向けサンプルコード付き

はじめに

C#のWindows Formsアプリで表形式のデータを表示したいときによく使われるのが、DataGridViewDataTableです。

DataGridViewは画面上に表を表示するためのコントロールで、DataTableはメモリ上で表形式のデータを管理するためのクラスです。この2つを組み合わせることで、データベースの検索結果やCSVの読み込み結果、アプリ内で作成した一覧データなどを簡単に画面へ表示できます。

特に初心者の方は、次のような場面で悩みやすいです。

「DataTableを作ったけれどDataGridViewに表示されない」

「DataGridViewで編集した値はDataTableに反映されるのか分からない」

「DataTableの追加・更新・削除をどう書けばよいか分からない」

「データベースの内容をDataTable経由でDataGridViewに表示したい」

この記事では、C#のDataGridViewDataTableを表示する基本から、編集内容の反映、行の追加・更新・削除、データベース連携、よくあるエラーの対処法まで、初心者向けにサンプルコード付きで解説します。

1. C#のDataGridViewにDataTableを表示する基本

1-1. DataGridViewとDataTableの役割

DataGridViewは、Windows Formsで表形式のデータを画面に表示するためのコントロールです。Excelのように行と列でデータを表示でき、セルの編集、行の選択、列幅の調整なども行えます。

一方、DataTableはC#で表形式のデータを扱うためのクラスです。DataTableには列を表すDataColumnと、行を表すDataRowがあります。

例えば、社員一覧を扱う場合は次のようなイメージです。

C#
DataTable table = new DataTable();

table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Age", typeof(int));

table.Rows.Add(1, "田中", 28);
table.Rows.Add(2, "佐藤", 35);
table.Rows.Add(3, "鈴木", 41);

このDataTableDataGridViewに設定すると、画面上に一覧表として表示できます。

C#
dataGridView1.DataSource = table;

C#でDataGridViewDataTableを使う基本は、このように「DataTableにデータを作る」「DataGridViewのDataSourceに設定する」という流れです。

1-2. DataTableを使うメリット

DataTableを使うメリットは、データを表形式で扱いやすいことです。

例えば、次のような処理が簡単にできます。

C#
DataTable table = new DataTable();
table.Columns.Add("ProductName", typeof(string));
table.Columns.Add("Price", typeof(int));

table.Rows.Add("ノートPC", 120000);
table.Rows.Add("マウス", 2500);

DataTableを使うと、行や列を自由に追加でき、データベースの検索結果をそのまま格納することもできます。

また、DataGridViewDataSourceDataTableを設定すると、DataTableの内容が自動的に画面へ反映されます。画面表示用のデータと、内部で管理するデータを分けて考えられるため、コードの見通しも良くなります。

1-3. DataGridView.DataSourceにDataTableを設定する流れ

DataGridViewDataTableを表示する基本的な流れは次のとおりです。

C#
private void Form1_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();

table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Age", typeof(int));

table.Rows.Add(1, "田中", 28);
table.Rows.Add(2, "佐藤", 35);
table.Rows.Add(3, "鈴木", 41);

dataGridView1.DataSource = table;
}

ポイントは、DataTableに列を追加してから行を追加することです。列を作成していない状態で行を追加しようとすると、データの格納先がないためエラーや意図しない動作の原因になります。

また、DataGridViewに表示するときは、最後に次の1行を書きます。

C#
dataGridView1.DataSource = table;

この1行によって、DataTableの内容がDataGridViewにバインドされます。

1-4. 初心者がつまずきやすいポイント

初心者がよくつまずくポイントの1つは、DataTableを作っただけではDataGridViewに表示されないという点です。

次のコードでは、DataTableは作成されていますが、DataGridViewには表示されません。

C#
DataTable table = new DataTable();
table.Columns.Add("Name", typeof(string));
table.Rows.Add("田中");

表示するには、必ずDataSourceに設定する必要があります。

C#
dataGridView1.DataSource = table;

また、DataSourceに設定した後で列名を変更したい場合は、DataTableの列名ではなく、DataGridView側のHeaderTextを変更することもあります。

C#
dataGridView1.Columns["Name"].HeaderText = "氏名";

さらに、編集した内容がすぐにDataTableへ反映されないように見える場合は、編集中のセルがまだ確定していない可能性があります。この場合は、EndEditを使って編集を確定します。

C#
dataGridView1.EndEdit();

2. DataTableを作成してDataGridViewに表示するサンプル

2-1. Windows Formsプロジェクトの準備

まず、Visual StudioでWindows Formsアプリのプロジェクトを作成します。

フォームにDataGridViewを1つ配置し、名前をdataGridView1にしておきます。初期状態では、ツールボックスからDataGridViewをドラッグ&ドロップするだけで問題ありません。

フォームの読み込み時にデータを表示したい場合は、Form1_Loadイベントにコードを書きます。

C#
private void Form1_Load(object sender, EventArgs e)
{
// ここにDataTable作成とDataGridView表示のコードを書く
}

DataTableを使うには、ファイルの先頭に次の名前空間を追加します。

C#
using System.Data;

2-2. DataTableに列を追加する方法

DataTableに列を追加するには、Columns.Addを使います。

C#
DataTable table = new DataTable();

table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Department", typeof(string));
table.Columns.Add("Salary", typeof(int));

第1引数には列名、第2引数にはデータ型を指定します。

例えば、Idは整数なのでtypeof(int)NameDepartmentは文字列なのでtypeof(string)を指定しています。

列名はプログラム内部で使う名前です。画面上に表示する日本語の見出しは、後からDataGridView側で設定できます。

2-3. DataTableに行を追加する方法

DataTableに行を追加するには、Rows.Addを使います。

C#
table.Rows.Add(1, "田中太郎", "営業部", 300000);
table.Rows.Add(2, "佐藤花子", "総務部", 280000);
table.Rows.Add(3, "鈴木一郎", "開発部", 350000);

Rows.Addに渡す値の順番は、Columns.Addで追加した列の順番と対応しています。

つまり、次の列定義の場合、

C#
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Department", typeof(string));
table.Columns.Add("Salary", typeof(int));

行を追加するときは、次の順番で値を指定します。

C#
table.Rows.Add(1, "田中太郎", "営業部", 300000);

順番を間違えると、意図しない列に値が入ったり、型の不一致でエラーになったりします。

2-4. DataGridViewにDataTableをバインドするコード

作成したDataTableDataGridViewに表示するには、DataSourceに設定します。

C#
using System;
using System.Data;
using System.Windows.Forms;

namespace DataGridViewDataTableSample
{
public partial class Form1 : Form
{
private DataTable employeeTable;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
employeeTable = new DataTable();

employeeTable.Columns.Add("Id", typeof(int));
employeeTable.Columns.Add("Name", typeof(string));
employeeTable.Columns.Add("Department", typeof(string));
employeeTable.Columns.Add("Salary", typeof(int));

employeeTable.Rows.Add(1, "田中太郎", "営業部", 300000);
employeeTable.Rows.Add(2, "佐藤花子", "総務部", 280000);
employeeTable.Rows.Add(3, "鈴木一郎", "開発部", 350000);

dataGridView1.DataSource = employeeTable;
}
}
}

このコードを実行すると、employeeTableの内容がdataGridView1に表示されます。

employeeTableをフィールドとして定義している理由は、後で追加・更新・削除などの処理を行うときにも同じDataTableを参照できるようにするためです。

2-5. 表示結果の確認

実行すると、DataGridViewには次のような内容が表示されます。

IdNameDepartmentSalary
1田中太郎営業部300000
2佐藤花子総務部280000
3鈴木一郎開発部350000

この時点で、DataGridViewDataTableの内容を表示しています。

DataGridView上でセルを編集できる設定になっていれば、セルの値を変更することもできます。編集した内容は、基本的にはバインド元であるDataTableにも反映されます。

3. DataGridViewの表示を見やすく設定する方法

3-1. 列名を変更する

DataTableの列名はプログラム内部で使いやすい英語名にしておき、画面上の見出しだけ日本語に変更することができます。

C#
dataGridView1.Columns["Id"].HeaderText = "社員ID";
dataGridView1.Columns["Name"].HeaderText = "氏名";
dataGridView1.Columns["Department"].HeaderText = "部署";
dataGridView1.Columns["Salary"].HeaderText = "給与";

このようにすると、DataTableの列名はIdNameのままですが、DataGridView上では「社員ID」「氏名」のように表示できます。

列名を直接日本語にすることもできます。

C#
table.Columns.Add("社員ID", typeof(int));
table.Columns.Add("氏名", typeof(string));

ただし、プログラム内で列名を指定して処理する場合は、英語名の方が扱いやすいことが多いです。

3-2. 列幅を自動調整する

DataGridViewの列幅を自動調整するには、AutoSizeColumnsModeを設定します。

C#
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

Fillを指定すると、DataGridView全体の幅に合わせて列幅が自動調整されます。

内容に合わせて列幅を調整したい場合は、次のようにします。

C#
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

よく使われる設定は次のとおりです。

設定値内容
Fill表全体の幅に合わせて列幅を調整
AllCellsヘッダーとセルの内容に合わせて調整
DisplayedCells表示中のセル内容に合わせて調整
None自動調整しない

画面いっぱいに表を表示したい場合は、Fillが使いやすいです。

3-3. 読み取り専用にする

DataGridViewで編集させたくない場合は、ReadOnlytrueにします。

C#
dataGridView1.ReadOnly = true;

これで、ユーザーはセルの値を変更できなくなります。

特定の列だけ読み取り専用にすることもできます。

C#
dataGridView1.Columns["Id"].ReadOnly = true;

例えば、社員IDのように変更されたくない列だけ読み取り専用にし、氏名や部署は編集可能にする、といった使い方ができます。

C#
dataGridView1.Columns["Id"].ReadOnly = true;
dataGridView1.Columns["Name"].ReadOnly = false;
dataGridView1.Columns["Department"].ReadOnly = false;
dataGridView1.Columns["Salary"].ReadOnly = false;

3-4. 行追加・削除の可否を設定する

DataGridViewでは、ユーザーによる行追加や行削除を制御できます。

行追加を禁止するには、次のようにします。

C#
dataGridView1.AllowUserToAddRows = false;

行削除を禁止するには、次のようにします。

C#
dataGridView1.AllowUserToDeleteRows = false;

両方を禁止する場合は、次のように設定します。

C#
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;

一覧表示だけを目的とする画面では、行追加や行削除を禁止しておくと誤操作を防ぎやすくなります。

3-5. 選択モードを設定する

DataGridViewでは、セル単位で選択するか、行全体を選択するかを設定できます。

行全体を選択したい場合は、SelectionModeを設定します。

C#
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

複数行選択を禁止したい場合は、MultiSelectfalseにします。

C#
dataGridView1.MultiSelect = false;

よく使う設定をまとめると、次のようになります。

C#
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;

この設定にすると、ユーザーは1行ずつ選択でき、不要な行追加や削除を防げます。

4. DataGridView上で編集した内容をDataTableに反映する

4-1. DataGridViewとDataTableのデータ連携の仕組み

DataGridViewDataSourceDataTableを設定すると、DataGridViewDataTableの内容を表示します。

C#
dataGridView1.DataSource = employeeTable;

この状態では、DataGridViewDataTableがバインドされています。

そのため、DataGridView上でセルの値を編集すると、バインド元であるDataTableにも変更が反映されます。

例えば、DataGridView上で「田中太郎」を「田中次郎」に変更した場合、employeeTable内の該当行のName列も変更されます。

ただし、セルを編集中の状態では、まだ値が確定していないことがあります。その場合、DataTableを確認しても古い値のままに見えることがあります。

4-2. セル編集後にDataTableへ反映されるタイミング

DataGridViewでセルを編集した値は、通常、セルの編集が終了したタイミングで反映されます。

例えば、次のような操作をしたときです。

  • Enterキーを押す

  • 別のセルへ移動する

  • 別の行へ移動する

  • フォーカスが移動する

逆に、セル内にカーソルが残っていて編集中の状態では、DataTable側にまだ反映されていない場合があります。

ボタンを押して変更内容を保存するような画面では、ボタンクリック時に編集を確定してからDataTableを確認するのが安全です。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();

// この後にDataTableの内容を確認・保存する
}

4-3. 編集中の値を確定する方法

編集中の値を確定するには、DataGridView.EndEditを使います。

C#
dataGridView1.EndEdit();

BindingSourceを使っている場合は、BindingSource.EndEditも呼び出すとより確実です。

C#
bindingSource1.EndEdit();

例えば、BindingSourceを使ってDataTableをバインドする場合は次のようになります。

C#
private DataTable employeeTable;
private BindingSource bindingSource;

private void Form1_Load(object sender, EventArgs e)
{
employeeTable = new DataTable();

employeeTable.Columns.Add("Id", typeof(int));
employeeTable.Columns.Add("Name", typeof(string));
employeeTable.Columns.Add("Department", typeof(string));

employeeTable.Rows.Add(1, "田中太郎", "営業部");
employeeTable.Rows.Add(2, "佐藤花子", "総務部");

bindingSource = new BindingSource();
bindingSource.DataSource = employeeTable;

dataGridView1.DataSource = bindingSource;
}

private void buttonSave_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();
bindingSource.EndEdit();

MessageBox.Show("編集内容を確定しました。");
}

DataGridViewDataTableの間にBindingSourceを挟むと、並び替えやフィルター、編集確定の管理がしやすくなります。

4-4. DataTableの変更内容を確認するサンプルコード

DataGridViewで編集した内容がDataTableに反映されているか確認するには、DataTableの行をループして値を取得します。

C#
private void buttonCheck_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();

foreach (DataRow row in employeeTable.Rows)
{
string message =
$"Id: {row["Id"]}, Name: {row["Name"]}, Department: {row["Department"]}";

MessageBox.Show(message);
}
}

DataGridViewの表示値ではなく、DataTableの中身を確認している点が重要です。

また、削除された行が含まれている場合、削除済み行に直接アクセスするとエラーになることがあります。その場合は、RowStateを確認します。

C#
foreach (DataRow row in employeeTable.Rows)
{
if (row.RowState == DataRowState.Deleted)
{
continue;
}

Console.WriteLine(row["Name"]);
}

4-5. GetChangesで変更行を取得する方法

DataTableには、変更された行だけを取得するGetChangesメソッドがあります。

C#
DataTable changedTable = employeeTable.GetChanges();

変更がない場合、GetChangesnullを返します。

C#
private void buttonGetChanges_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();

DataTable changedTable = employeeTable.GetChanges();

if (changedTable == null)
{
MessageBox.Show("変更された行はありません。");
return;
}

foreach (DataRow row in changedTable.Rows)
{
MessageBox.Show($"状態: {row.RowState}");
}
}

RowStateを見ることで、その行が追加されたのか、更新されたのか、削除されたのかを判断できます。

RowState意味
Added追加された行
Modified更新された行
Deleted削除された行
Unchanged変更されていない行

データベースへ変更内容を保存するときは、このRowStateをもとにInsert、Update、Deleteを判断することが多いです。

5. DataTableのデータを追加・更新・削除する方法

5-1. DataTableに新しい行を追加する

DataTableに新しい行を追加するには、Rows.Addを使います。

C#
private void buttonAdd_Click(object sender, EventArgs e)
{
employeeTable.Rows.Add(4, "高橋美咲", "経理部", 310000);
}

DataGridViewDataTableにバインドされていれば、DataTableに行を追加したタイミングでDataGridViewにも反映されます。

NewRowを使って行を作成する方法もあります。

C#
private void buttonAdd_Click(object sender, EventArgs e)
{
DataRow newRow = employeeTable.NewRow();

newRow["Id"] = 4;
newRow["Name"] = "高橋美咲";
newRow["Department"] = "経理部";
newRow["Salary"] = 310000;

employeeTable.Rows.Add(newRow);
}

列数が多い場合や、列名を指定して値を入れたい場合は、NewRowを使う方法が分かりやすいです。

5-2. 指定した行の値を更新する

指定した行の値を更新するには、対象のDataRowを取得して値を変更します。

例えば、先頭行の氏名を変更する場合は次のように書きます。

C#
private void buttonUpdate_Click(object sender, EventArgs e)
{
employeeTable.Rows[0]["Name"] = "田中次郎";
}

条件に一致する行を探して更新する場合は、Selectを使えます。

C#
private void buttonUpdate_Click(object sender, EventArgs e)
{
DataRow[] rows = employeeTable.Select("Id = 2");

if (rows.Length > 0)
{
rows[0]["Department"] = "人事部";
rows[0]["Salary"] = 300000;
}
}

Selectの条件式では、列名と値を使って対象行を検索できます。

文字列で検索する場合は、値をシングルクォートで囲みます。

C#
DataRow[] rows = employeeTable.Select("Name = '佐藤花子'");

5-3. 指定した行を削除する

DataTableから行を削除する方法には、主にDeleteRemoveがあります。

Deleteは行を削除済み状態にします。

C#
employeeTable.Rows[0].Delete();

Removeは行をコレクションから取り除きます。

C#
employeeTable.Rows.Remove(employeeTable.Rows[0]);

データベース更新と連携する場合は、Deleteを使うことが多いです。理由は、Deleteを使うとRowStateDeletedになり、後から削除された行として判断できるためです。

C#
private void buttonDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
return;
}

int rowIndex = dataGridView1.CurrentRow.Index;

if (rowIndex >= 0 && rowIndex < employeeTable.Rows.Count)
{
employeeTable.Rows[rowIndex].Delete();
}
}

ただし、DataGridViewの行インデックスとDataTableの行インデックスは、並び替えをしている場合に一致しないことがあります。より安全に削除するには、DataBoundItemからDataRowViewを取得します。

C#
private void buttonDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
return;
}

DataRowView rowView = dataGridView1.CurrentRow.DataBoundItem as DataRowView;

if (rowView != null)
{
rowView.Row.Delete();
}
}

5-4. DataGridViewの表示を更新する

通常、DataTableに行を追加・更新・削除すると、バインドされているDataGridViewも自動的に更新されます。

しかし、表示が変わらない場合は、DataSourceを再設定する方法があります。

C#
dataGridView1.DataSource = null;
dataGridView1.DataSource = employeeTable;

BindingSourceを使っている場合は、ResetBindingsを呼び出します。

C#
bindingSource.ResetBindings(false);

例えば、次のように使います。

C#
private void buttonRefresh_Click(object sender, EventArgs e)
{
bindingSource.ResetBindings(false);
}

ただし、毎回DataSourceを設定し直すと、列幅や選択状態がリセットされることがあります。基本的には、DataTableを直接変更し、必要な場合だけResetBindingsを使うのがおすすめです。

5-5. AcceptChangesとRejectChangesの違い

DataTableには、変更状態を確定するAcceptChangesと、変更を取り消すRejectChangesがあります。

AcceptChangesを呼び出すと、追加・更新・削除などの変更状態が確定され、RowStateUnchangedになります。

C#
employeeTable.AcceptChanges();

一方、RejectChangesを呼び出すと、変更内容が取り消されます。

C#
employeeTable.RejectChanges();

例えば、次のような使い方ができます。

C#
private void buttonAccept_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();
employeeTable.AcceptChanges();

MessageBox.Show("変更を確定しました。");
}

private void buttonReject_Click(object sender, EventArgs e)
{
employeeTable.RejectChanges();

MessageBox.Show("変更を取り消しました。");
}

注意点として、データベースに保存する前にAcceptChangesを呼び出すと、どの行が追加・更新・削除されたのか分からなくなる場合があります。

データベース更新を行う場合は、基本的に保存処理が成功してからAcceptChangesを呼び出します。

6. データベースのデータをDataTable経由でDataGridViewに表示する

6-1. SQL Serverからデータを取得する基本

C#でSQL Serverのデータを取得してDataGridViewに表示する場合も、DataTableを使うと分かりやすくなります。

基本的な流れは次のとおりです。

  1. SQL Serverへ接続する

  2. SQLを実行してデータを取得する

  3. 取得結果をDataTableに読み込む

  4. DataGridView.DataSourceDataTableを設定する

SQL Serverへ接続するには、接続文字列が必要です。

C#
string connectionString =
@"Data Source=.\SQLEXPRESS;Initial Catalog=SampleDb;Integrated Security=True;";

環境によって、サーバー名やデータベース名は変わります。

SQL Server認証を使う場合は、次のような形式になります。

C#
string connectionString =
@"Data Source=localhost;Initial Catalog=SampleDb;User ID=sa;Password=your_password;";

実際のアプリでは、パスワードをソースコードに直接書かず、設定ファイルなどで管理する方が安全です。

6-2. SqlDataAdapterでDataTableに読み込む

SQL Serverの検索結果をDataTableに読み込むには、SqlDataAdapterを使う方法が簡単です。

C#
using System.Data;
using System.Data.SqlClient;

サンプルコードは次のとおりです。

C#
private DataTable LoadEmployees()
{
string connectionString =
@"Data Source=.\SQLEXPRESS;Initial Catalog=SampleDb;Integrated Security=True;";

string sql = "SELECT Id, Name, Department, Salary FROM Employees";

DataTable table = new DataTable();

using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlDataAdapter adapter = new SqlDataAdapter(sql, connection))
{
adapter.Fill(table);
}

return table;
}

adapter.Fill(table)を実行すると、SQLの実行結果がDataTableに読み込まれます。

この方法では、SqlConnectionOpenを明示的に書かなくても、SqlDataAdapterが必要に応じて接続を開いて閉じてくれます。

6-3. DataGridViewに検索結果を表示する

取得したDataTableDataGridViewに表示するには、これまでと同じようにDataSourceへ設定します。

C#
private DataTable employeeTable;

private void Form1_Load(object sender, EventArgs e)
{
employeeTable = LoadEmployees();
dataGridView1.DataSource = employeeTable;
}

検索ボタンを押したときに表示する場合は、次のように書けます。

C#
private void buttonSearch_Click(object sender, EventArgs e)
{
employeeTable = LoadEmployees();
dataGridView1.DataSource = employeeTable;
}

部署名で検索したい場合は、SQLに条件を追加します。

C#
private DataTable SearchEmployees(string department)
{
string connectionString =
@"Data Source=.\SQLEXPRESS;Initial Catalog=SampleDb;Integrated Security=True;";

string sql = "SELECT Id, Name, Department, Salary FROM Employees WHERE Department = @Department";

DataTable table = new DataTable();

using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlDataAdapter adapter = new SqlDataAdapter(sql, connection))
{
adapter.SelectCommand.Parameters.AddWithValue("@Department", department);
adapter.Fill(table);
}

return table;
}

画面側では次のように呼び出します。

C#
private void buttonSearch_Click(object sender, EventArgs e)
{
string department = textBoxDepartment.Text;

employeeTable = SearchEmployees(department);
dataGridView1.DataSource = employeeTable;
}

SQLに値を埋め込むとSQLインジェクションの原因になるため、検索条件にはパラメーターを使うようにします。

6-4. DataTableの変更内容をデータベースに更新する

DataTableの変更内容をSQL Serverへ反映するには、SqlDataAdapterUpdateを使う方法があります。

簡単なサンプルとして、SqlCommandBuilderを使う方法を紹介します。

C#
private SqlDataAdapter adapter;
private DataTable employeeTable;

private void Form1_Load(object sender, EventArgs e)
{
string connectionString =
@"Data Source=.\SQLEXPRESS;Initial Catalog=SampleDb;Integrated Security=True;";

string sql = "SELECT Id, Name, Department, Salary FROM Employees";

adapter = new SqlDataAdapter(sql, connectionString);

SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

employeeTable = new DataTable();
adapter.Fill(employeeTable);

dataGridView1.DataSource = employeeTable;
}

保存ボタンでは、次のようにUpdateを呼び出します。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();

adapter.Update(employeeTable);

MessageBox.Show("データベースを更新しました。");
}

SqlCommandBuilderを使うと、単純なSELECT文からInsert、Update、Delete用のSQLを自動生成できます。

ただし、実務では複雑なテーブル構造や業務ルールがあるため、Insert、Update、Delete用のSQLを自分で明示的に書くことも多いです。

6-5. Insert・Update・Deleteの考え方

DataTableでは、各行にRowStateという状態があります。

新しく追加された行はAdded、編集された行はModified、削除された行はDeletedになります。

C#
foreach (DataRow row in employeeTable.Rows)
{
Console.WriteLine(row.RowState);
}

データベースに反映するときは、この状態を見て次のように処理を分けます。

RowStateデータベース処理
AddedINSERT
ModifiedUPDATE
DeletedDELETE

手動で処理を書く場合のイメージは次のとおりです。

C#
foreach (DataRow row in employeeTable.Rows)
{
if (row.RowState == DataRowState.Added)
{
// INSERT処理
}
else if (row.RowState == DataRowState.Modified)
{
// UPDATE処理
}
else if (row.RowState == DataRowState.Deleted)
{
// DELETE処理
}
}

削除された行の値を取得する場合は、DataRowVersion.Originalを使います。

C#
if (row.RowState == DataRowState.Deleted)
{
int id = (int)row["Id", DataRowVersion.Original];

// idを使ってDELETEする
}

更新前の値と更新後の値を比較したい場合も、DataRowVersionを使います。

C#
if (row.RowState == DataRowState.Modified)
{
string oldName = row["Name", DataRowVersion.Original].ToString();
string newName = row["Name", DataRowVersion.Current].ToString();
}

7. DataGridViewとDataTableでよくあるエラーと対処法

7-1. DataSourceに設定しても表示されない

DataGridView.DataSourceDataTableを設定しても表示されない場合は、まずDataTableに列と行が入っているか確認します。

C#
MessageBox.Show($"列数: {employeeTable.Columns.Count}, 行数: {employeeTable.Rows.Count}");

列がない場合、DataGridViewには表示する項目がありません。

また、AutoGenerateColumnsfalseになっている場合、自動で列が生成されません。

C#
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = employeeTable;

フォーム上に配置したDataGridViewとは別のインスタンスにDataSourceを設定していないかも確認しましょう。

例えば、次のように新しくDataGridViewを作ってしまうと、画面上のdataGridView1には表示されません。

C#
DataGridView grid = new DataGridView();
grid.DataSource = employeeTable;

画面に配置したdataGridView1へ設定する必要があります。

C#
dataGridView1.DataSource = employeeTable;

7-2. 編集した値が反映されない

DataGridViewで編集した値がDataTableに反映されない場合は、編集が確定していない可能性があります。

保存ボタンなどの処理では、最初にEndEditを呼び出します。

C#
private void buttonSave_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();

// DataTableの内容を確認・保存する
}

BindingSourceを使っている場合は、次のようにします。

C#
dataGridView1.EndEdit();
bindingSource.EndEdit();

また、DataGridViewが読み取り専用になっている場合、そもそも編集できません。

C#
dataGridView1.ReadOnly = false;

列単位で読み取り専用になっていないかも確認します。

C#
dataGridView1.Columns["Name"].ReadOnly = false;

7-3. 列名が意図した表示にならない

DataTableの列名を英語で作成している場合、DataGridView上にも英語名が表示されます。

C#
table.Columns.Add("Name", typeof(string));

画面上の見出しを日本語にしたい場合は、HeaderTextを変更します。

C#
dataGridView1.Columns["Name"].HeaderText = "氏名";

ただし、DataSourceを設定する前にColumns["Name"]へアクセスすると、列がまだ作成されていないためエラーになることがあります。

正しい順番は次のとおりです。

C#
dataGridView1.DataSource = employeeTable;

dataGridView1.Columns["Id"].HeaderText = "社員ID";
dataGridView1.Columns["Name"].HeaderText = "氏名";

また、AutoGenerateColumnsfalseにしている場合は、手動で列を作成し、DataPropertyNameを設定する必要があります。

C#
dataGridView1.AutoGenerateColumns = false;

DataGridViewTextBoxColumn nameColumn = new DataGridViewTextBoxColumn();
nameColumn.HeaderText = "氏名";
nameColumn.DataPropertyName = "Name";

dataGridView1.Columns.Add(nameColumn);
dataGridView1.DataSource = employeeTable;

DataPropertyNameには、DataTableの列名を指定します。ここを間違えると、列は表示されても値が表示されません。

7-4. Null値でエラーになる

DataTableの値がnullDBNull.Valueの場合、文字列や数値に変換するときにエラーになることがあります。

データベースから読み込んだ値がNULLの場合、C#では多くの場合DBNull.Valueとして扱われます。

例えば、次のようなコードはエラーになる可能性があります。

C#
int salary = (int)row["Salary"];

NULLの可能性がある場合は、DBNull.Valueかどうか確認します。

C#
int salary = 0;

if (row["Salary"] != DBNull.Value)
{
salary = Convert.ToInt32(row["Salary"]);
}

文字列の場合は、次のように書くと安全です。

C#
string name = row["Name"] == DBNull.Value
? string.Empty
: row["Name"].ToString();

DataTableの列にNULLを許可したくない場合は、AllowDBNullfalseにできます。

C#
DataColumn nameColumn = new DataColumn("Name", typeof(string));
nameColumn.AllowDBNull = false;

employeeTable.Columns.Add(nameColumn);

ただし、NULLを禁止した列に値を入れずに行を追加するとエラーになります。

7-5. データ更新後に画面が変わらない

DataTableの値を変更したのにDataGridViewの表示が変わらない場合は、バインドの状態を確認します。

BindingSourceを使っている場合は、ResetBindingsを呼び出します。

C#
bindingSource.ResetBindings(false);

直接DataTableを設定している場合は、DataSourceを再設定する方法もあります。

C#
dataGridView1.DataSource = null;
dataGridView1.DataSource = employeeTable;

ただし、通常はDataTableの行や列を正しく変更していれば、自動的に反映されます。

次のように、DataTableではなく別の変数を変更しているだけでは、DataGridViewには反映されません。

C#
string name = employeeTable.Rows[0]["Name"].ToString();
name = "変更後の名前";

この場合、変数nameを変更しただけで、DataTableの値は変わっていません。

正しくは、DataRowの値を変更します。

C#
employeeTable.Rows[0]["Name"] = "変更後の名前";

また、データベースを更新しただけでは、画面上のDataTableが自動的に最新になるとは限りません。データベース更新後に最新データを再取得する場合は、再度検索処理を実行します。

C#
private void buttonReload_Click(object sender, EventArgs e)
{
employeeTable = LoadEmployees();
dataGridView1.DataSource = employeeTable;
}

まとめ

C#でDataGridViewDataTableを表示する基本は、DataTableに列と行を作成し、DataGridView.DataSourceに設定することです。

C#
dataGridView1.DataSource = employeeTable;

DataTableを使うことで、メモリ上で表形式のデータを管理しながら、DataGridViewに簡単に表示できます。

基本的な流れは次のとおりです。

C#
DataTable table = new DataTable();

table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));

table.Rows.Add(1, "田中");
table.Rows.Add(2, "佐藤");

dataGridView1.DataSource = table;

DataGridView上で編集した内容は、基本的にバインド元のDataTableへ反映されます。ただし、編集中の値を確実に反映したい場合は、保存処理の前にEndEditを呼び出します。

C#
dataGridView1.EndEdit();

また、DataTableの行を追加・更新・削除すると、バインドされているDataGridViewにも表示が反映されます。

C#
employeeTable.Rows.Add(4, "高橋美咲", "経理部", 310000);
employeeTable.Rows[0]["Name"] = "田中次郎";
employeeTable.Rows[1].Delete();

データベースのデータを表示する場合は、SqlDataAdapterで検索結果をDataTableに読み込み、DataGridViewに設定します。

C#
SqlDataAdapter adapter = new SqlDataAdapter(sql, connectionString);
DataTable table = new DataTable();

adapter.Fill(table);

dataGridView1.DataSource = table;

C#のWindows Formsで一覧画面を作る場合、DataGridViewDataTableの組み合わせは非常に便利です。まずは小さなサンプルで表示、編集、追加、更新、削除の流れを理解し、その後でデータベース連携に進むとスムーズに学習できます。