C# DataGridViewの使い方完全ガイド|表示・追加・編集・削除・エラー対処まで解説
はじめに
C#でWindowsフォームアプリを作るとき、表形式のデータを表示・編集する代表的なコントロールがDataGridViewです。
顧客一覧、商品一覧、売上一覧、CSVのプレビュー、データベース検索結果の表示など、業務アプリでは非常によく使われます。
一方で、C# DataGridViewはできることが多い分、初心者がつまずきやすいポイントもあります。
たとえば、次のような悩みはよくあります。
「DataGridViewにデータを表示する方法が分からない」
「Rows.Addで行を追加しようとしたらエラーになる」
「選択行を削除したいが、DataSourceを使っている場合の処理が分からない」
「セルの編集結果を取得したい」
「DataGridViewComboBoxCellの値が無効というエラーが出る」
この記事では、C# DataGridViewの基本的な使い方から、表示、追加、編集、削除、検索、ソート、データベース連携、エラー対処までをまとめて解説します。
1. C# DataGridViewとは?できることと検索ユーザーの前提知識
1-1. DataGridViewはWindowsフォームで表データを表示・編集するコントロール
DataGridViewは、C#のWindowsフォームアプリで表形式のデータを扱うためのコントロールです。
Excelのように、行と列で構成されたデータを画面上に表示できます。
たとえば、次のようなデータを表示できます。
| ID | 名前 | 年齢 | 部署 |
|---|---|---|---|
| 1 | 田中 | 30 | 営業 |
| 2 | 佐藤 | 25 | 開発 |
| 3 | 鈴木 | 28 | 経理 |
DataGridViewは単に表を表示するだけでなく、セルの編集、行の追加、行の削除、チェックボックス列、コンボボックス列、ボタン列などにも対応しています。
そのため、C#で業務アプリを作る場合には非常に重要なコントロールです。
1-2. DataGridViewでできること:表示・追加・編集・削除・検索・ソート
DataGridViewでは、主に次のような処理ができます。
データを一覧表示する。
ユーザーが行やセルを選択する。
セルの値を編集する。
新しい行を追加する。
選択した行を削除する。
キーワードで検索する。
条件に一致する行だけ絞り込む。
列ヘッダーをクリックしてソートする。
チェックボックス、コンボボックス、ボタンを列として表示する。
データベースやCSVファイルと連携する。
C# DataGridViewを使えるようになると、一覧画面、マスタ管理画面、検索画面、編集画面などを効率よく作れるようになります。
1-3. ListView・DataTable・DataGridとの違い
DataGridViewと似た名前のものに、ListView、DataTable、DataGridがあります。
ListViewは、一覧表示に向いたコントロールです。アイコン表示やリスト表示には便利ですが、表形式の編集機能はDataGridViewほど強くありません。
DataTableは、画面部品ではなく、メモリ上で表データを管理するためのクラスです。DataGridViewのDataSourceにDataTableを設定すると、DataTableの内容を画面に表示できます。
DataGridは、古い.NET Framework時代からある表形式コントロールです。Windowsフォームでは、現在はDataGridViewを使うのが一般的です。
つまり、画面に表を表示・編集したい場合はDataGridView、内部的に表データを持ちたい場合はDataTable、と考えると分かりやすいです。
1-4. DataGridViewを使うべきケースと向いていないケース
DataGridViewが向いているのは、次のようなケースです。
業務アプリで一覧画面を作りたい場合。
データベースの検索結果を表示したい場合。
CSVやExcel風の表データを画面に表示したい場合。
ユーザーにセルを編集させたい場合。
行単位で追加・編集・削除を行いたい場合。
一方、DataGridViewが向いていないケースもあります。
スマートフォン向けUIのような柔軟なデザインが必要な場合。
複雑なカード型レイアウトを表示したい場合。
数十万件以上のデータをそのまま全件表示したい場合。
WPFアプリでMVVMを前提に作る場合。
WPFではDataGridを使うのが一般的です。WindowsフォームアプリならDataGridViewが定番です。
2. DataGridViewを使う準備
2-1. Windowsフォームアプリを作成する
Visual StudioでC# DataGridViewを使うには、まずWindowsフォームアプリを作成します。
新しいプロジェクトを作成し、テンプレートから「Windows フォーム アプリ」を選択します。
.NET Framework版でも、.NET版のWindows FormsでもDataGridViewは利用できます。
プロジェクトを作成すると、Form1.csというフォームが作成されます。このフォーム上にDataGridViewを配置して使います。
2-2. Visual StudioでDataGridViewをフォームに配置する
Visual Studioのデザイナー画面でDataGridViewを配置する手順は次のとおりです。
ツールボックスを開く。
「DataGridView」を探す。
フォーム上にドラッグ&ドロップする。
プロパティウィンドウでNameを変更する。
たとえば、NameをdataGridView1のまま使うこともできますが、実務ではdgvEmployeesやdgvProductsのように、用途が分かる名前にするのがおすすめです。
2-3. コードからDataGridViewを生成する方法
DataGridViewはデザイナーから配置するだけでなく、コードから生成することもできます。
C#DataGridView dgv = new DataGridView();
dgv.Name = "dgvEmployees";
dgv.Location = new Point(20, 20);
dgv.Size = new Size(600, 300);
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
this.Controls.Add(dgv);
コードで生成する方法は、動的に画面を作りたい場合や、共通部品としてDataGridViewを生成したい場合に便利です。
通常の業務アプリでは、まずはデザイナーで配置して使う方法から覚えるとよいでしょう。
2-4. よく使う基本プロパティ一覧
DataGridViewでよく使う基本プロパティをまとめます。
| プロパティ | 内容 |
|---|---|
| DataSource | 表示するデータソースを設定する |
| ReadOnly | 編集不可にする |
| AllowUserToAddRows | ユーザーによる行追加を許可する |
| AllowUserToDeleteRows | ユーザーによる行削除を許可する |
| AutoGenerateColumns | DataSourceから列を自動生成する |
| AutoSizeColumnsMode | 列幅の自動調整方法 |
| SelectionMode | 選択方法を指定する |
| MultiSelect | 複数選択を許可する |
| CurrentRow | 現在選択されている行 |
| CurrentCell | 現在選択されているセル |
| Rows | 行コレクション |
| Columns | 列コレクション |
特に重要なのは、DataSourceを使うかどうかです。
DataSourceを使わない場合は、Rows.Addで直接行を追加できます。
DataSourceを使う場合は、元データであるDataTableやListを操作するのが基本です。
2-5. サンプルで使うデータ構成
この記事では、社員データを例にして解説します。
C#public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
public string Department { get; set; } = "";
}
このようなクラスを使うと、List<Employee>やBindingList<Employee>をDataGridViewに表示できます。
DataTableを使う場合は、次のような構成を想定します。
C#DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Age", typeof(int));
table.Columns.Add("Department", typeof(string));
3. DataGridViewにデータを表示する基本
3-1. 列を手動で追加して表示する
DataGridViewにデータを表示する最も基本的な方法は、列を手動で追加してから行を追加する方法です。
C#dataGridView1.Columns.Clear();
dataGridView1.Columns.Add("Id", "ID");
dataGridView1.Columns.Add("Name", "名前");
dataGridView1.Columns.Add("Age", "年齢");
dataGridView1.Columns.Add("Department", "部署");
第1引数は列の内部名、第2引数は画面に表示されるヘッダー名です。
列を手動で追加する方法は、DataSourceを使わずに簡単な一覧を作る場合に向いています。
3-2. Rows.Addで行を追加して表示する
列を追加したら、Rows.Addで行を追加できます。
C#dataGridView1.Rows.Add(1, "田中", 30, "営業");
dataGridView1.Rows.Add(2, "佐藤", 25, "開発");
dataGridView1.Rows.Add(3, "鈴木", 28, "経理");
これでDataGridViewに3行のデータが表示されます。
ただし、DataSourceを設定しているDataGridViewに対してRows.Addを実行するとエラーになることがあります。
DataSourceを使う場合は、DataGridViewではなく元データに行を追加する必要があります。
3-3. DataTableをDataSourceに設定して表示する
DataGridViewでは、DataTableをDataSourceに設定して表示する方法がよく使われます。
C#DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Name", typeof(string));
table.Columns.Add("Age", typeof(int));
table.Columns.Add("Department", typeof(string));
table.Rows.Add(1, "田中", 30, "営業");
table.Rows.Add(2, "佐藤", 25, "開発");
table.Rows.Add(3, "鈴木", 28, "経理");
dataGridView1.DataSource = table;
DataTableを使うと、検索、絞り込み、ソート、データベース連携がしやすくなります。
業務アプリでSQL結果をDataGridViewに表示する場合も、DataTableを経由することが多いです。
3-4. ListやBindingListをDataSourceに設定して表示する
クラスのリストをDataGridViewに表示することもできます。
C#List<Employee> employees = new List<Employee>
{
new Employee { Id = 1, Name = "田中", Age = 30, Department = "営業" },
new Employee { Id = 2, Name = "佐藤", Age = 25, Department = "開発" },
new Employee { Id = 3, Name = "鈴木", Age = 28, Department = "経理" }
};
dataGridView1.DataSource = employees;
ただし、通常のList<T>は、後から要素を追加してもDataGridViewに自動反映されないことがあります。
追加や削除を画面に反映したい場合は、BindingList<T>を使うと便利です。
C#BindingList<Employee> employees = new BindingList<Employee>
{
new Employee { Id = 1, Name = "田中", Age = 30, Department = "営業" },
new Employee { Id = 2, Name = "佐藤", Age = 25, Department = "開発" }
};
dataGridView1.DataSource = employees;
employees.Add(new Employee { Id = 3, Name = "鈴木", Age = 28, Department = "経理" });
BindingList<T>を使うと、データ追加がDataGridViewに反映されやすくなります。
3-5. AutoGenerateColumnsで列を自動生成する
AutoGenerateColumnsは、DataSourceを設定したときに列を自動生成するかどうかを指定するプロパティです。
C#dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = employees;
trueにすると、Employeeクラスのプロパティに応じて列が自動生成されます。
自分で列を定義したい場合は、falseにします。
C#dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = "Id",
HeaderText = "ID",
Name = "Id"
});
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
{
DataPropertyName = "Name",
HeaderText = "名前",
Name = "Name"
});
dataGridView1.DataSource = employees;
DataPropertyNameには、バインドするプロパティ名やDataTableの列名を指定します。
3-6. 表示だけにしたい場合のReadOnly設定
DataGridViewを表示専用にしたい場合は、ReadOnlyをtrueにします。
C#dataGridView1.ReadOnly = true;
さらに、ユーザーによる行追加や削除も禁止したい場合は、次のように設定します。
C#dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
一覧表示だけの画面では、この3つをセットで使うことが多いです。
C#dataGridView1.ReadOnly = true;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
4. DataGridViewの行・列・セルを操作する方法
4-1. 行を追加する方法
DataSourceを使っていない場合は、Rows.Addで行を追加できます。
C#dataGridView1.Rows.Add(4, "高橋", 32, "総務");
DataTableをDataSourceにしている場合は、DataTableに行を追加します。
C#DataTable table = (DataTable)dataGridView1.DataSource;
table.Rows.Add(4, "高橋", 32, "総務");
BindingListをDataSourceにしている場合は、BindingListに追加します。
C#BindingList<Employee> employees = (BindingList<Employee>)dataGridView1.DataSource;
employees.Add(new Employee
{
Id = 4,
Name = "高橋",
Age = 32,
Department = "総務"
});
DataGridViewを使うときは、「画面に直接追加するのか」「DataSourceに追加するのか」を意識することが重要です。
4-2. 行を削除する方法
DataSourceを使っていない場合は、Rows.Removeで削除できます。
C#if (dataGridView1.CurrentRow != null)
{
dataGridView1.Rows.Remove(dataGridView1.CurrentRow);
}
ただし、最下行の新規入力行を削除しようとするとエラーになることがあります。
C#if (dataGridView1.CurrentRow != null && !dataGridView1.CurrentRow.IsNewRow)
{
dataGridView1.Rows.Remove(dataGridView1.CurrentRow);
}
DataTableをDataSourceにしている場合は、DataRowを削除します。
C#if (dataGridView1.CurrentRow != null)
{
DataRowView rowView = dataGridView1.CurrentRow.DataBoundItem as DataRowView;
if (rowView != null)
{
rowView.Row.Delete();
}
}
4-3. 選択中の行を取得する方法
選択中の行は、CurrentRowまたはSelectedRowsで取得できます。
1行だけ選択する場合はCurrentRowが簡単です。
C#DataGridViewRow row = dataGridView1.CurrentRow;
if (row != null)
{
string name = row.Cells["Name"].Value?.ToString() ?? "";
MessageBox.Show(name);
}
複数行選択を使う場合は、SelectedRowsを使います。
C#foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
if (!row.IsNewRow)
{
string name = row.Cells["Name"].Value?.ToString() ?? "";
Console.WriteLine(name);
}
}
行全体を選択しやすくするには、次の設定をしておくと便利です。
C#dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
4-4. セルの値を取得・変更する方法
セルの値を取得するには、Cellsを使います。
C#object value = dataGridView1.Rows[0].Cells[1].Value;
列名で指定することもできます。
C#string name = dataGridView1.Rows[0].Cells["Name"].Value?.ToString() ?? "";
セルの値を変更するには、Valueに代入します。
C#dataGridView1.Rows[0].Cells["Name"].Value = "山田";
ただし、DataSourceを使っている場合は、画面のセル値だけを変更するより、元データを変更する方が安全です。
4-5. 行番号・列番号を指定して操作する方法
行番号と列番号を指定してセルを操作できます。
C#int rowIndex = 0;
int columnIndex = 1;
dataGridView1.Rows[rowIndex].Cells[columnIndex].Value = "変更後の値";
ただし、インデックスは0から始まります。
1行目はRows[0]、2行目はRows[1]です。
存在しない行番号や列番号を指定すると、IndexOutOfRangeExceptionが発生します。
安全に操作するには、件数を確認してからアクセスします。
C#if (dataGridView1.Rows.Count > rowIndex &&
dataGridView1.Columns.Count > columnIndex)
{
dataGridView1.Rows[rowIndex].Cells[columnIndex].Value = "変更後の値";
}
4-6. 空行を非表示にする方法
DataGridViewの最下行に表示される空白行は、新規行追加用の行です。
これを非表示にするには、AllowUserToAddRowsをfalseにします。
C#dataGridView1.AllowUserToAddRows = false;
一覧表示だけの画面では、ほとんどの場合この設定を入れておくと見た目がすっきりします。
4-7. 行追加・行削除を禁止する方法
ユーザーによる行追加を禁止するには、次のように設定します。
C#dataGridView1.AllowUserToAddRows = false;
ユーザーによる行削除を禁止するには、次のように設定します。
C#dataGridView1.AllowUserToDeleteRows = false;
セル編集も含めてすべて禁止したい場合は、ReadOnlyも設定します。
C#dataGridView1.ReadOnly = true;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
5. DataGridViewで編集機能を実装する
5-1. セル編集を有効・無効にする
DataGridViewのセル編集を有効にするには、ReadOnlyをfalseにします。
C#dataGridView1.ReadOnly = false;
編集不可にするには、trueにします。
C#dataGridView1.ReadOnly = true;
編集画面ではReadOnly = false、参照画面ではReadOnly = trueにするのが基本です。
5-2. 特定の列だけ編集不可にする
ID列など、特定の列だけ編集不可にしたい場合は、列のReadOnlyを設定します。
C#dataGridView1.Columns["Id"].ReadOnly = true;
たとえば、社員IDは変更不可にして、名前や部署だけ編集可能にする場合に使います。
C#dataGridView1.ReadOnly = false;
dataGridView1.Columns["Id"].ReadOnly = true;
全体のReadOnlyがtrueになっていると、列単位でReadOnly = falseにしても編集できません。
全体は編集可能にして、編集不可にしたい列だけReadOnly = trueにします。
5-3. 編集完了時に値を取得する
セルの編集後に値を取得したい場合は、CellEndEditイベントやCellValueChangedイベントを使います。
C#private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
object value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
MessageBox.Show($"編集後の値: {value}");
}
CellEndEditは、セル編集が終了したタイミングで発生します。
編集中の値を確定させた後に処理したい場合に使いやすいイベントです。
5-4. CellValueChangedイベントの使い方
CellValueChangedイベントは、セルの値が変更されたときに発生します。
C#private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || e.ColumnIndex < 0)
{
return;
}
object value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
Console.WriteLine($"変更されました: {value}");
}
注意点として、チェックボックス列の場合、クリックしただけではすぐにCellValueChangedが発生しないことがあります。
その場合は、CurrentCellDirtyStateChangedで編集を確定します。
C#private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
チェックボックス列を使う場合は、この組み合わせを覚えておくと便利です。
5-5. 入力チェックを実装する
入力チェックには、CellValidatingイベントを使います。
たとえば、年齢列に数値以外が入力された場合にエラーを表示する例です。
C#private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Age")
{
string input = e.FormattedValue?.ToString() ?? "";
if (!int.TryParse(input, out int age))
{
MessageBox.Show("年齢には数値を入力してください。");
e.Cancel = true;
return;
}
if (age < 0)
{
MessageBox.Show("年齢には0以上の数値を入力してください。");
e.Cancel = true;
}
}
}
e.Cancel = trueにすると、入力エラーのセルから移動できなくなります。
入力チェックを入れることで、型変換エラーや保存時の不正データを防げます。
5-6. 編集内容をDataTableやListに反映する
DataTableをDataSourceに設定している場合、DataGridView上で編集した内容はDataTableにも反映されます。
C#DataTable table = (DataTable)dataGridView1.DataSource;
ただし、編集中のセルが確定していない場合、値が反映されていないことがあります。
保存前に次の処理を入れると安全です。
C#dataGridView1.EndEdit();
BindingSourceを使っている場合は、次のようにします。
C#bindingSource1.EndEdit();
List<T>やBindingList<T>を使っている場合も、プロパティに値が反映されます。
ただし、クラスのプロパティがget; set;になっている必要があります。
5-7. 編集内容をDBやファイルへ保存する考え方
DataGridViewは画面表示用のコントロールです。
そのため、編集した内容を永続化したい場合は、DataGridViewそのものではなく、元データを保存します。
DataTableを使っている場合は、DataTableの内容をSQLやCSVに保存します。
Listを使っている場合は、Listの内容をファイルやDBに保存します。
実務では、次の流れで考えると整理しやすくなります。
画面に表示するデータを用意する。
DataGridViewにバインドする。
ユーザーが編集する。
編集内容を元データに反映する。
保存ボタンでDBやファイルに保存する。
DataGridViewのセル値を直接DBに保存するより、元データを通して保存する方が保守しやすくなります。
6. DataGridViewの削除処理を安全に実装する
6-1. 選択行を削除する基本コード
DataSourceを使っていない場合、選択行を削除する基本コードは次のとおりです。
C#private void btnDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
MessageBox.Show("削除する行を選択してください。");
return;
}
if (dataGridView1.CurrentRow.IsNewRow)
{
return;
}
dataGridView1.Rows.Remove(dataGridView1.CurrentRow);
}
IsNewRowを確認することで、最下行の空白行を削除しようとして発生するエラーを防げます。
6-2. 複数行を削除する方法
複数行を削除する場合は、SelectedRowsを使います。
C#foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
if (!row.IsNewRow)
{
dataGridView1.Rows.Remove(row);
}
}
複数選択を有効にするには、次の設定をします。
C#dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = true;
DataSourceなしの場合はこれで削除できます。
DataSourceありの場合は、元データ側から削除する必要があります。
6-3. 削除前に確認ダイアログを表示する
削除処理では、誤操作を防ぐために確認ダイアログを表示するのがおすすめです。
C#private void btnDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null || dataGridView1.CurrentRow.IsNewRow)
{
MessageBox.Show("削除する行を選択してください。");
return;
}
DialogResult result = MessageBox.Show(
"選択した行を削除しますか?",
"確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
dataGridView1.Rows.Remove(dataGridView1.CurrentRow);
}
}
業務アプリでは削除処理の取り消しが難しいことも多いため、確認ダイアログを入れておくと安全です。
6-4. DataSourceあり・なしで削除方法が異なる理由
DataGridViewには、大きく分けて2つの使い方があります。
DataSourceを使わず、DataGridViewに直接行を追加する方法。
DataTableやListをDataSourceに設定する方法。
DataSourceを使わない場合、DataGridView自体が行データを持っているため、Rows.Removeで削除できます。
一方、DataSourceを使っている場合、実際のデータはDataTableやList側にあります。
そのため、DataGridViewの行だけを削除しようとするとエラーになったり、データとの整合性が崩れたりします。
DataSourceありの場合は、基本的に元データを操作します。
C#DataRowView rowView = dataGridView1.CurrentRow.DataBoundItem as DataRowView;
if (rowView != null)
{
rowView.Delete();
}
BindingListの場合は、DataBoundItemを取得して削除します。
C#BindingList<Employee> employees = (BindingList<Employee>)dataGridView1.DataSource;
Employee employee = dataGridView1.CurrentRow.DataBoundItem as Employee;
if (employee != null)
{
employees.Remove(employee);
}
6-5. 削除時に発生しやすいエラーと対処法
削除時によくあるエラーには、次のようなものがあります。
選択行がないのに削除しようとしてエラーになる。
最下行の新規入力行を削除しようとしてエラーになる。
DataSource設定中にRows.Removeを使ってエラーになる。
複数行削除中にコレクションが変化してエラーになる。
対処法としては、次の点を確認します。
CurrentRowがnullでないか確認する。
IsNewRowを確認する。
DataSourceありの場合は元データから削除する。
複数削除では削除対象を一度リスト化してから削除する。
C#var rows = dataGridView1.SelectedRows
.Cast<DataGridViewRow>()
.Where(r => !r.IsNewRow)
.ToList();
foreach (var row in rows)
{
dataGridView1.Rows.Remove(row);
}
7. DataGridViewの見た目を整える
7-1. 列幅を自動調整する
列幅を自動調整するには、AutoSizeColumnsModeを設定します。
C#dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
よく使う設定は次のとおりです。
| 値 | 内容 |
|---|---|
| Fill | 全体幅に合わせて列幅を調整 |
| AllCells | すべてのセル内容に合わせる |
| DisplayedCells | 表示中のセル内容に合わせる |
| ColumnHeader | ヘッダー文字に合わせる |
| None | 自動調整しない |
画面幅いっぱいに表示したい場合はFillが便利です。
7-2. ヘッダー名を変更する
列ヘッダー名を変更するには、HeaderTextを設定します。
C#dataGridView1.Columns["Id"].HeaderText = "社員ID";
dataGridView1.Columns["Name"].HeaderText = "氏名";
dataGridView1.Columns["Age"].HeaderText = "年齢";
dataGridView1.Columns["Department"].HeaderText = "部署";
DataSourceの列名やプロパティ名をそのまま表示すると、英語名になることがあります。
ユーザー向け画面では、日本語のヘッダー名に変更すると分かりやすくなります。
7-3. 行の高さ・フォント・文字位置を変更する
行の高さを変更するには、RowTemplate.Heightを使います。
C#dataGridView1.RowTemplate.Height = 28;
フォントを変更するには、DefaultCellStyle.Fontを設定します。
C#dataGridView1.DefaultCellStyle.Font = new Font("Meiryo", 10);
dataGridView1.ColumnHeadersDefaultCellStyle.Font = new Font("Meiryo", 10, FontStyle.Bold);
文字位置を変更するには、Alignmentを使います。
C#dataGridView1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
数値列だけ右寄せにする場合は、列単位で設定します。
C#dataGridView1.Columns["Age"].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
7-4. セルの背景色や文字色を変更する
DataGridView全体の背景色や文字色を変えるには、DefaultCellStyleを使います。
C#dataGridView1.DefaultCellStyle.BackColor = Color.White;
dataGridView1.DefaultCellStyle.ForeColor = Color.Black;
交互に行の背景色を変えるには、AlternatingRowsDefaultCellStyleを使います。
C#dataGridView1.AlternatingRowsDefaultCellStyle.BackColor = Color.LightGray;
特定の条件で色を変える場合は、CellFormattingイベントを使います。
C#private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Age")
{
if (e.Value != null && int.TryParse(e.Value.ToString(), out int age))
{
if (age >= 30)
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightYellow;
}
}
}
}
条件付きで色を変えると、注意が必要なデータを見つけやすくなります。
7-5. 日付・数値・金額の表示形式を設定する
日付や数値は、DefaultCellStyle.Formatで表示形式を設定できます。
C#dataGridView1.Columns["Birthday"].DefaultCellStyle.Format = "yyyy/MM/dd";
dataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";
dataGridView1.Columns["Amount"].DefaultCellStyle.Format = "C";
N0は3桁区切りの整数表示です。
Cは通貨形式です。
金額を円表示にしたい場合は、カルチャ設定や文字列加工を組み合わせることもあります。
C#dataGridView1.Columns["Price"].DefaultCellStyle.Format = "#,##0円";
7-6. 左端の行ヘッダーを非表示にする
DataGridViewの左端には、行ヘッダーが表示されます。
不要な場合は非表示にできます。
C#dataGridView1.RowHeadersVisible = false;
業務アプリの一覧画面では、行ヘッダーを非表示にすることが多いです。
7-7. チェックボックス列・コンボボックス列・ボタン列を追加する
チェックボックス列を追加するには、DataGridViewCheckBoxColumnを使います。
C#DataGridViewCheckBoxColumn checkColumn = new DataGridViewCheckBoxColumn();
checkColumn.Name = "Selected";
checkColumn.HeaderText = "選択";
dataGridView1.Columns.Add(checkColumn);
コンボボックス列を追加するには、DataGridViewComboBoxColumnを使います。
C#DataGridViewComboBoxColumn comboColumn = new DataGridViewComboBoxColumn();
comboColumn.Name = "Department";
comboColumn.HeaderText = "部署";
comboColumn.Items.AddRange("営業", "開発", "経理", "総務");
dataGridView1.Columns.Add(comboColumn);
ボタン列を追加するには、DataGridViewButtonColumnを使います。
C#DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
buttonColumn.Name = "Detail";
buttonColumn.HeaderText = "詳細";
buttonColumn.Text = "表示";
buttonColumn.UseColumnTextForButtonValue = true;
dataGridView1.Columns.Add(buttonColumn);
ボタンがクリックされたときの処理は、CellContentClickイベントで判定します。
C#private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
if (dataGridView1.Columns[e.ColumnIndex].Name == "Detail")
{
MessageBox.Show("詳細ボタンがクリックされました。");
}
}
8. DataGridViewで検索・絞り込み・ソートを実装する
8-1. セルをループしてキーワード検索する
DataSourceを使わずに単純な検索をする場合は、セルをループしてキーワードを探します。
C#string keyword = textBoxSearch.Text;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.IsNewRow)
{
continue;
}
foreach (DataGridViewCell cell in row.Cells)
{
string value = cell.Value?.ToString() ?? "";
if (value.Contains(keyword))
{
row.Selected = true;
dataGridView1.CurrentCell = row.Cells[0];
return;
}
}
}
MessageBox.Show("該当データが見つかりません。");
少量データであれば、この方法でも十分です。
8-2. 検索結果の行を選択・ハイライトする
検索に一致した行をハイライトするには、行の背景色を変更します。
C#string keyword = textBoxSearch.Text;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.IsNewRow)
{
continue;
}
row.DefaultCellStyle.BackColor = Color.White;
foreach (DataGridViewCell cell in row.Cells)
{
string value = cell.Value?.ToString() ?? "";
if (value.Contains(keyword))
{
row.DefaultCellStyle.BackColor = Color.Yellow;
break;
}
}
}
検索結果を選択するだけでなく、色で分かるようにすると使いやすくなります。
8-3. DataView.RowFilterで絞り込みする
DataTableを使っている場合は、DataView.RowFilterで絞り込みできます。
C#DataTable table = (DataTable)dataGridView1.DataSource;
DataView view = table.DefaultView;
string keyword = textBoxSearch.Text.Replace("'", "''");
view.RowFilter = $"Name LIKE '%{keyword}%'";
複数列を対象にする場合は、OR条件を使います。
C#view.RowFilter = $"Name LIKE '%{keyword}%' OR Department LIKE '%{keyword}%'";
RowFilterを解除するには、空文字を設定します。
C#view.RowFilter = "";
DataTableを使っている場合、DataGridView上で行を非表示にするより、DataViewで絞り込む方が管理しやすいです。
8-4. LINQで検索する
List<T>を使っている場合は、LINQで検索できます。
C#List<Employee> employees = GetEmployees();
string keyword = textBoxSearch.Text;
var result = employees
.Where(x => x.Name.Contains(keyword) || x.Department.Contains(keyword))
.ToList();
dataGridView1.DataSource = result;
元の一覧に戻したい場合は、元データを再設定します。
C#dataGridView1.DataSource = employees;
LINQは条件を柔軟に書けるため、オブジェクトのリストを扱う場合に便利です。
8-5. 列ヘッダークリックでソートする
DataTableをDataSourceにしている場合、列ヘッダーをクリックすると自動でソートできることがあります。
手動でソートする場合は、次のようにします。
C#dataGridView1.Sort(
dataGridView1.Columns["Name"],
ListSortDirection.Ascending);
DataTableの場合は、DataViewのSortを使う方法もあります。
C#DataTable table = (DataTable)dataGridView1.DataSource;
table.DefaultView.Sort = "Name ASC";
降順にする場合はDESCを使います。
C#table.DefaultView.Sort = "Age DESC";
8-6. 大量データ検索で重くなる場合の対策
大量データをDataGridViewに表示して検索すると、画面が重くなることがあります。
対策としては、次の方法があります。
最初から全件表示せず、検索条件を指定してから表示する。
SQL側でWHERE句を使って絞り込む。
ページング処理を入れる。
VirtualModeを使う。
検索中は描画更新を抑える。
DataGridViewは便利ですが、数十万件のデータをそのまま表示する用途には向いていません。
実務では、画面に表示する件数を制限し、必要なデータだけ取得する設計が重要です。
9. DataGridViewとデータベースを連携する
9-1. DataTableにSQL結果を表示する基本
データベースの検索結果をDataGridViewに表示する場合、よく使われる流れは次のとおりです。
SQLを実行する。
結果をDataTableに格納する。
DataGridViewのDataSourceにDataTableを設定する。
基本形は次のようになります。
C#DataTable table = new DataTable();
// ここでSQLの結果をtableに読み込む
dataGridView1.DataSource = table;
データベース連携では、DataGridViewに直接データを入れるのではなく、DataTableを経由するのが一般的です。
9-2. SQL ServerのデータをDataGridViewに表示する
SQL Serverのデータを表示する例です。
C#using Microsoft.Data.SqlClient;
using System.Data;
private void LoadEmployees()
{
string connectionString = "Server=localhost;Database=SampleDb;Trusted_Connection=True;TrustServerCertificate=True;";
string sql = "SELECT Id, Name, Age, Department FROM Employees";
using SqlConnection connection = new SqlConnection(connectionString);
using SqlDataAdapter adapter = new SqlDataAdapter(sql, connection);
DataTable table = new DataTable();
adapter.Fill(table);
dataGridView1.DataSource = table;
}
SQL Serverに接続する場合は、接続文字列を環境に合わせて変更してください。
ログインIDとパスワードを使う場合は、接続文字列も変わります。
9-3. SQLiteのデータをDataGridViewに表示する
SQLiteのデータを表示する例です。
C#using Microsoft.Data.Sqlite;
using System.Data;
private void LoadEmployees()
{
string connectionString = "Data Source=sample.db";
string sql = "SELECT Id, Name, Age, Department FROM Employees";
DataTable table = new DataTable();
using SqliteConnection connection = new SqliteConnection(connectionString);
connection.Open();
using SqliteCommand command = new SqliteCommand(sql, connection);
using SqliteDataReader reader = command.ExecuteReader();
table.Load(reader);
dataGridView1.DataSource = table;
}
SQLiteはローカルファイルで扱えるため、小規模なWindowsフォームアプリやツールで使いやすいデータベースです。
9-4. 追加・編集・削除をDBへ反映する流れ
DataGridView上で追加、編集、削除した内容をDBへ反映するには、主に次の方法があります。
保存ボタンを押したタイミングで、DataTableの内容を確認してSQLを実行する。
追加ボタン、更新ボタン、削除ボタンごとにSQLを実行する。
SqlDataAdapterとCommandBuilderを使ってDataTableの変更をDBに反映する。
実務では、画面操作ごとにSQLを明示的に実行する方法が分かりやすいです。
たとえば、更新処理は次のように書けます。
C#private void UpdateEmployee(int id, string name, int age, string department)
{
string connectionString = "Server=localhost;Database=SampleDb;Trusted_Connection=True;TrustServerCertificate=True;";
string sql = @"
UPDATE Employees
SET Name = @Name,
Age = @Age,
Department = @Department
WHERE Id = @Id";
using SqlConnection connection = new SqlConnection(connectionString);
using SqlCommand command = new SqlCommand(sql, connection);
command.Parameters.AddWithValue("@Id", id);
command.Parameters.AddWithValue("@Name", name);
command.Parameters.AddWithValue("@Age", age);
command.Parameters.AddWithValue("@Department", department);
connection.Open();
command.ExecuteNonQuery();
}
SQLを文字列連結で作るとSQLインジェクションの危険があるため、パラメータを使うようにしましょう。
9-5. DB連携時の注意点
DataGridViewとDBを連携するときは、次の点に注意します。
SQLはパラメータ化する。
表示用の列とDB更新用の主キーを分ける。
削除時は本当に削除するのか、論理削除にするのかを決める。
画面表示後にDB側のデータが変更される可能性を考える。
大量データを全件表示しない。
例外処理を入れる。
保存前にEndEditで編集中の値を確定する。
C#dataGridView1.EndEdit();
DataGridViewは画面操作の入口であり、DB更新の責任をすべてDataGridViewに持たせないことが重要です。
10. DataGridViewでよく使うイベント一覧
10-1. CellClickイベント
CellClickは、セルがクリックされたときに発生します。
C#private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
string value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value?.ToString() ?? "";
MessageBox.Show(value);
}
ヘッダーがクリックされた場合、RowIndexが-1になるため注意が必要です。
10-2. CellContentClickイベント
CellContentClickは、セルの内容部分がクリックされたときに発生します。
ボタン列やリンク列を使うときによく使います。
C#private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0)
{
return;
}
if (dataGridView1.Columns[e.ColumnIndex].Name == "Detail")
{
MessageBox.Show("詳細を表示します。");
}
}
10-3. CellValueChangedイベント
CellValueChangedは、セルの値が変更されたときに発生します。
C#private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || e.ColumnIndex < 0)
{
return;
}
Console.WriteLine("セルの値が変更されました。");
}
チェックボックス列では、CommitEditと組み合わせることがあります。
10-4. CellValidatingイベント
CellValidatingは、セルの入力値を検証するときに使います。
C#private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Name")
{
string input = e.FormattedValue?.ToString() ?? "";
if (string.IsNullOrWhiteSpace(input))
{
MessageBox.Show("名前を入力してください。");
e.Cancel = true;
}
}
}
入力必須チェックや数値チェックに便利です。
10-5. SelectionChangedイベント
SelectionChangedは、選択行や選択セルが変わったときに発生します。
C#private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
return;
}
string name = dataGridView1.CurrentRow.Cells["Name"].Value?.ToString() ?? "";
textBoxName.Text = name;
}
選択行の内容をTextBoxに表示するような画面でよく使います。
10-6. UserDeletingRowイベント
UserDeletingRowは、ユーザーが行を削除しようとしたときに発生します。
C#private void dataGridView1_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
DialogResult result = MessageBox.Show(
"この行を削除しますか?",
"確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result != DialogResult.Yes)
{
e.Cancel = true;
}
}
Deleteキーによる削除を制御したい場合に使えます。
10-7. DataErrorイベント
DataErrorは、DataGridViewでデータ関連のエラーが発生したときに呼ばれます。
型変換エラーやコンボボックス列の値不一致などを処理できます。
C#private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
MessageBox.Show("入力値またはデータに問題があります。");
Console.WriteLine(e.Exception?.Message);
e.ThrowException = false;
}
DataGridViewを実務で使う場合、DataErrorイベントを用意しておくと予期しないエラーでアプリが落ちるのを防ぎやすくなります。
11. DataGridViewでよくあるエラーと対処法
11-1. Rows.Addできないエラーの原因と対処法
DataGridViewでよくあるのが、Rows.Addを実行したときのエラーです。
主な原因は、DataSourceが設定されていることです。
C#dataGridView1.DataSource = table;
dataGridView1.Rows.Add(1, "田中"); // エラーになることがある
DataSourceを使っている場合は、DataGridViewではなくDataTableに行を追加します。
C#DataTable table = (DataTable)dataGridView1.DataSource;
table.Rows.Add(1, "田中");
DataSourceありなら元データを操作する、DataSourceなしならRows.Addを使う、と覚えておきましょう。
11-2. IndexOutOfRangeExceptionが出る原因と対処法
IndexOutOfRangeExceptionは、存在しない行番号や列番号を指定したときに発生します。
C#dataGridView1.Rows[10].Cells[0].Value = "test";
行が10件未満の場合、このコードはエラーになります。
対処法は、事前に件数を確認することです。
C#int rowIndex = 10;
if (rowIndex >= 0 && rowIndex < dataGridView1.Rows.Count)
{
dataGridView1.Rows[rowIndex].Cells[0].Value = "test";
}
また、ヘッダークリック時のRowIndex = -1にも注意します。
C#if (e.RowIndex < 0)
{
return;
}
11-3. NullReferenceExceptionが出る原因と対処法
NullReferenceExceptionは、nullのオブジェクトにアクセスしたときに発生します。
DataGridViewでは、次のような場面で起こりやすいです。
選択行がないのにCurrentRowへアクセスする。
セルのValueがnullなのにToString()する。
DataSourceがnullなのにキャストする。
安全に書くには、nullチェックを入れます。
C#if (dataGridView1.CurrentRow == null)
{
return;
}
string name = dataGridView1.CurrentRow.Cells["Name"].Value?.ToString() ?? "";
?.や??を使うと、nullによるエラーを防ぎやすくなります。
11-4. DataSource設定後に列や行を追加できない場合の対処法
DataSourceを設定した後に、DataGridViewへ直接行を追加しようとするとエラーになることがあります。
これは、DataGridViewのデータ管理がDataSource側に移るためです。
対処法は、元データを操作することです。
DataTableの場合は、DataTableに列や行を追加します。
C#DataTable table = (DataTable)dataGridView1.DataSource;
table.Columns.Add("Memo", typeof(string));
table.Rows.Add(4, "高橋", 32, "総務", "メモ");
列を画面上だけ追加したい場合は、DataSource設定前に列を作るか、AutoGenerateColumns = falseにして手動定義します。
C#dataGridView1.AutoGenerateColumns = false;
DataSourceを使う場合は、DataGridViewと元データのどちらを操作すべきかを常に意識しましょう。
11-5. 入力値の型変換エラーへの対処法
DataTableの列がint型なのに、文字列を入力すると型変換エラーが発生することがあります。
たとえば、Age列がint型の場合に「abc」と入力するとエラーになります。
対処法は、CellValidatingで事前にチェックすることです。
C#private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "Age")
{
string input = e.FormattedValue?.ToString() ?? "";
if (!int.TryParse(input, out _))
{
MessageBox.Show("数値を入力してください。");
e.Cancel = true;
}
}
}
さらに、DataErrorイベントも用意しておくと安全です。
C#private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
MessageBox.Show("入力値の形式が正しくありません。");
e.ThrowException = false;
}
11-6. DataGridViewComboBoxCellの値が無効になるエラー
DataGridViewComboBoxColumnでよくあるのが、セルの値がコンボボックスの候補に存在しないために発生するエラーです。
たとえば、コンボボックスの候補が「営業」「開発」「経理」だけなのに、データ側に「総務」が入っているとエラーになることがあります。
対処法は、データに存在する値をコンボボックスの候補にも追加することです。
C#DataGridViewComboBoxColumn comboColumn = new DataGridViewComboBoxColumn();
comboColumn.Name = "Department";
comboColumn.HeaderText = "部署";
comboColumn.Items.AddRange("営業", "開発", "経理", "総務");
DataSourceを使う場合は、DisplayMember、ValueMember、セルの値の型が一致しているかも確認します。
C#comboColumn.DataSource = departmentTable;
comboColumn.DisplayMember = "Name";
comboColumn.ValueMember = "Code";
comboColumn.DataPropertyName = "DepartmentCode";
ComboBox列では、表示名と実際の値の対応関係を正しくそろえることが重要です。
11-7. DataErrorイベントで例外を処理する方法
DataGridViewの実務利用では、DataErrorイベントを入れておくことをおすすめします。
C#private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
string message = e.Exception?.Message ?? "DataGridViewでエラーが発生しました。";
Console.WriteLine(message);
MessageBox.Show(
"データの表示または入力値に問題があります。",
"エラー",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
e.ThrowException = false;
}
e.ThrowException = falseにすることで、例外を再スローせず、アプリの強制終了を防ぎやすくなります。
ただし、DataErrorで握りつぶすだけでは根本原因は解決しません。
開発中はConsole.WriteLineやログ出力で原因を確認しましょう。
12. DataGridViewを実務で使いやすくするテクニック
12-1. データ件数を表示する
DataGridViewに表示されている件数をラベルに表示すると便利です。
C#labelCount.Text = $"{dataGridView1.Rows.Cast<DataGridViewRow>().Count(r => !r.IsNewRow)}件";
DataTableを使っている場合は、DataViewの件数を表示できます。
C#DataTable table = (DataTable)dataGridView1.DataSource;
labelCount.Text = $"{table.DefaultView.Count}件";
検索や絞り込み後に件数を更新すると、ユーザーにとって分かりやすい画面になります。
12-2. クリックした行の詳細をTextBoxに表示する
一覧で選択した行の内容をTextBoxに表示する例です。
C#private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
return;
}
textBoxId.Text = dataGridView1.CurrentRow.Cells["Id"].Value?.ToString() ?? "";
textBoxName.Text = dataGridView1.CurrentRow.Cells["Name"].Value?.ToString() ?? "";
textBoxAge.Text = dataGridView1.CurrentRow.Cells["Age"].Value?.ToString() ?? "";
textBoxDepartment.Text = dataGridView1.CurrentRow.Cells["Department"].Value?.ToString() ?? "";
}
一覧と詳細入力欄を組み合わせると、マスタ管理画面を作りやすくなります。
12-3. 右クリックメニューを追加する
DataGridViewに右クリックメニューを追加するには、ContextMenuStripを使います。
C#ContextMenuStrip menu = new ContextMenuStrip();
menu.Items.Add("削除", null, DeleteMenu_Click);
dataGridView1.ContextMenuStrip = menu;
右クリックした行を選択するには、CellMouseDownイベントを使います。
C#private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right && e.RowIndex >= 0)
{
dataGridView1.ClearSelection();
dataGridView1.Rows[e.RowIndex].Selected = true;
dataGridView1.CurrentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
}
}
右クリックメニューを使うと、削除、コピー、詳細表示などの操作を自然に追加できます。
12-4. CSVファイルを読み込んで表示する
CSVファイルを読み込んでDataTableに入れ、DataGridViewに表示する簡単な例です。
C#private void LoadCsv(string path)
{
DataTable table = new DataTable();
string[] lines = File.ReadAllLines(path, Encoding.UTF8);
if (lines.Length == 0)
{
return;
}
string[] headers = lines[0].Split(',');
foreach (string header in headers)
{
table.Columns.Add(header);
}
for (int i = 1; i < lines.Length; i++)
{
string[] values = lines[i].Split(',');
table.Rows.Add(values);
}
dataGridView1.DataSource = table;
}
この例は単純なCSV向けです。
値の中にカンマやダブルクォーテーションが含まれる本格的なCSVを扱う場合は、CSVパーサーの利用を検討してください。
12-5. DataGridViewの内容をCSVへ出力する
DataGridViewの内容をCSVへ出力する例です。
C#private void SaveCsv(string path)
{
StringBuilder sb = new StringBuilder();
var headers = dataGridView1.Columns
.Cast<DataGridViewColumn>()
.Where(c => c.Visible)
.Select(c => c.HeaderText);
sb.AppendLine(string.Join(",", headers));
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.IsNewRow)
{
continue;
}
var values = dataGridView1.Columns
.Cast<DataGridViewColumn>()
.Where(c => c.Visible)
.Select(c => row.Cells[c.Index].Value?.ToString() ?? "");
sb.AppendLine(string.Join(",", values));
}
File.WriteAllText(path, sb.ToString(), Encoding.UTF8);
}
値にカンマや改行が含まれる場合は、ダブルクォーテーションで囲むなどのエスケープ処理が必要です。
12-6. 印刷やExcel出力を行う場合の考え方
DataGridViewの内容を印刷したりExcel出力したりする場合、DataGridViewから直接処理するより、元データを使う方が安定します。
DataTableをExcelに出力する。
ListをCSVに変換する。
帳票ライブラリを使って印刷する。
Excelファイルを作成するライブラリを使う。
DataGridViewはあくまで画面表示用です。
出力処理では、表示中のセルを直接読むのではなく、DataTableやListなどの元データを基準にした方が保守しやすくなります。
12-7. 大量データ表示時のパフォーマンス改善
DataGridViewで大量データを扱う場合、次のような対策が有効です。
表示件数を制限する。
ページングを実装する。
SQL側で絞り込む。
不要な列を表示しない。
AutoSizeColumnsModeを使いすぎない。
CellFormattingで重い処理をしない。
VirtualModeを検討する。
特にAutoSizeColumnsMode = AllCellsは、データ件数が多いと重くなることがあります。
大量データではDisplayedCellsや固定幅を使う方がよい場合があります。
13. 初心者がつまずきやすいポイント
13-1. DataSourceありとなしの違いを理解する
C# DataGridViewで最も重要なのは、DataSourceありとなしの違いです。
DataSourceなしの場合は、DataGridViewに直接列や行を追加します。
C#dataGridView1.Columns.Add("Name", "名前");
dataGridView1.Rows.Add("田中");
DataSourceありの場合は、DataTableやListをDataGridViewに設定します。
C#dataGridView1.DataSource = table;
DataSourceありの状態でRows.Addを使おうとするとエラーになることがあります。
まずは、自分のDataGridViewがどちらの使い方なのかを確認しましょう。
13-2. 表示用データと保存用データを分けて考える
DataGridViewは画面表示用の部品です。
保存すべきデータは、DataGridViewではなくDataTable、List、DBなどにあります。
実務では、次のように役割を分けると分かりやすいです。
DataGridViewは表示と入力を担当する。
DataTableやListはアプリ内のデータを担当する。
DBやファイルは保存を担当する。
この分担を意識すると、編集や保存の処理が整理しやすくなります。
13-3. イベントの発火タイミングに注意する
DataGridViewには多くのイベントがありますが、発火タイミングが少し分かりにくいものもあります。
CellClickはクリック時に発生します。
CellEndEditは編集終了時に発生します。
CellValueChangedは値が変更されたときに発生します。
CellValidatingは入力検証時に発生します。
SelectionChangedは選択が変わったときに発生します。
特にチェックボックス列では、クリック直後に値が確定していないことがあります。
その場合は、CommitEditを使って値を確定させます。
13-4. セルの値はobject型で取得されることに注意する
DataGridViewのセル値は、基本的にobject型で取得されます。
C#object value = dataGridView1.CurrentRow.Cells["Age"].Value;
数値として使う場合は、型変換が必要です。
C#int age = Convert.ToInt32(dataGridView1.CurrentRow.Cells["Age"].Value);
ただし、nullや空文字が入っている可能性もあるため、実務ではTryParseを使うと安全です。
C#string text = dataGridView1.CurrentRow.Cells["Age"].Value?.ToString() ?? "";
if (int.TryParse(text, out int age))
{
MessageBox.Show($"年齢: {age}");
}
13-5. UI操作とデータ更新処理を混在させすぎない
初心者のうちは、DataGridViewのイベント内にDB更新やファイル保存まで直接書いてしまいがちです。
小さなサンプルでは問題ありませんが、処理が増えると保守しにくくなります。
おすすめは、画面操作とデータ処理を分けることです。
ボタンイベントでは入力値を取得する。
入力チェックを行う。
保存処理用のメソッドを呼び出す。
DB更新は別メソッドにまとめる。
このように分けると、エラー対応や機能追加がしやすくなります。
14. C# DataGridViewのサンプルコード集
14-1. 最小構成の表示サンプル
DataGridViewに列と行を追加して表示する最小サンプルです。
C#private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.Columns.Add("Id", "ID");
dataGridView1.Columns.Add("Name", "名前");
dataGridView1.Columns.Add("Age", "年齢");
dataGridView1.Rows.Add(1, "田中", 30);
dataGridView1.Rows.Add(2, "佐藤", 25);
dataGridView1.Rows.Add(3, "鈴木", 28);
dataGridView1.AllowUserToAddRows = false;
}
まずDataGridViewの動きを確認したい場合は、この形から始めると分かりやすいです。
14-2. 行追加のサンプル
TextBoxに入力した内容をDataGridViewに追加する例です。
C#private void btnAdd_Click(object sender, EventArgs e)
{
string name = textBoxName.Text;
string ageText = textBoxAge.Text;
if (string.IsNullOrWhiteSpace(name))
{
MessageBox.Show("名前を入力してください。");
return;
}
if (!int.TryParse(ageText, out int age))
{
MessageBox.Show("年齢には数値を入力してください。");
return;
}
int id = dataGridView1.Rows.Cast<DataGridViewRow>().Count(r => !r.IsNewRow) + 1;
dataGridView1.Rows.Add(id, name, age);
}
入力チェックを入れてから追加するのがポイントです。
14-3. 行編集のサンプル
選択行の値をTextBoxの内容で更新する例です。
C#private void btnUpdate_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null || dataGridView1.CurrentRow.IsNewRow)
{
MessageBox.Show("更新する行を選択してください。");
return;
}
if (!int.TryParse(textBoxAge.Text, out int age))
{
MessageBox.Show("年齢には数値を入力してください。");
return;
}
dataGridView1.CurrentRow.Cells["Name"].Value = textBoxName.Text;
dataGridView1.CurrentRow.Cells["Age"].Value = age;
}
DataSourceありの場合は、元データを更新する形に変えます。
14-4. 行削除のサンプル
選択行を確認付きで削除する例です。
C#private void btnDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null || dataGridView1.CurrentRow.IsNewRow)
{
MessageBox.Show("削除する行を選択してください。");
return;
}
DialogResult result = MessageBox.Show(
"選択した行を削除しますか?",
"確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
dataGridView1.Rows.Remove(dataGridView1.CurrentRow);
}
}
削除処理では、選択行チェックと確認ダイアログを入れると安全です。
14-5. 検索・絞り込みのサンプル
DataTableとRowFilterを使った検索サンプルです。
C#private DataTable employeeTable;
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("Age", typeof(int));
employeeTable.Columns.Add("Department", typeof(string));
employeeTable.Rows.Add(1, "田中", 30, "営業");
employeeTable.Rows.Add(2, "佐藤", 25, "開発");
employeeTable.Rows.Add(3, "鈴木", 28, "経理");
dataGridView1.DataSource = employeeTable;
}
private void btnSearch_Click(object sender, EventArgs e)
{
string keyword = textBoxSearch.Text.Replace("'", "''");
if (string.IsNullOrWhiteSpace(keyword))
{
employeeTable.DefaultView.RowFilter = "";
}
else
{
employeeTable.DefaultView.RowFilter =
$"Name LIKE '%{keyword}%' OR Department LIKE '%{keyword}%'";
}
}
DataTableを使うと、絞り込み処理を簡潔に書けます。
14-6. エラー処理を含めた実用サンプル
入力チェック、削除確認、DataErrorを含めた実用的なサンプルです。
C#private DataTable employeeTable;
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("Age", typeof(int));
employeeTable.Columns.Add("Department", typeof(string));
employeeTable.Rows.Add(1, "田中", 30, "営業");
employeeTable.Rows.Add(2, "佐藤", 25, "開発");
dataGridView1.DataSource = employeeTable;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
dataGridView1.Columns["Id"].ReadOnly = true;
}
private void btnAdd_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(textBoxName.Text))
{
MessageBox.Show("名前を入力してください。");
return;
}
if (!int.TryParse(textBoxAge.Text, out int age))
{
MessageBox.Show("年齢には数値を入力してください。");
return;
}
int id = employeeTable.Rows.Count + 1;
employeeTable.Rows.Add(id, textBoxName.Text, age, textBoxDepartment.Text);
}
private void btnDelete_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null)
{
MessageBox.Show("削除する行を選択してください。");
return;
}
DialogResult result = MessageBox.Show(
"選択した行を削除しますか?",
"確認",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result != DialogResult.Yes)
{
return;
}
DataRowView rowView = dataGridView1.CurrentRow.DataBoundItem as DataRowView;
if (rowView != null)
{
rowView.Row.Delete();
}
}
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
MessageBox.Show("入力値に問題があります。");
e.ThrowException = false;
}
このように、DataTableをDataSourceにしておくと、追加や削除の管理がしやすくなります。
15. C# DataGridViewに関するよくある質問
15-1. DataGridViewにデータが表示されない原因は?
DataGridViewにデータが表示されない場合、まず次の点を確認します。
DataSourceに正しいデータが設定されているか。
DataTableに行が入っているか。
AutoGenerateColumnsがfalseなのに列を定義していないのではないか。
DataPropertyNameが間違っていないか。
フォームのLoadイベントが正しく登録されているか。
特に、AutoGenerateColumns = falseにした場合は、列のDataPropertyNameを正しく設定する必要があります。
C#column.DataPropertyName = "Name";
プロパティ名や列名と一致していないと、データが表示されません。
15-2. 最下行の空白行を消すには?
最下行の空白行は、新規行追加用の行です。
非表示にするには、次の設定をします。
C#dataGridView1.AllowUserToAddRows = false;
一覧表示だけのDataGridViewでは、この設定を入れることが多いです。
15-3. セルを編集できないようにするには?
DataGridView全体を編集不可にするには、ReadOnlyをtrueにします。
C#dataGridView1.ReadOnly = true;
特定の列だけ編集不可にするには、列のReadOnlyを設定します。
C#dataGridView1.Columns["Id"].ReadOnly = true;
ユーザーによる行追加や削除も禁止する場合は、次の設定も追加します。
C#dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
15-4. 選択行の値を取得するには?
選択行の値は、CurrentRowから取得できます。
C#if (dataGridView1.CurrentRow != null)
{
string name = dataGridView1.CurrentRow.Cells["Name"].Value?.ToString() ?? "";
MessageBox.Show(name);
}
列名ではなく列番号でも取得できます。
C#string value = dataGridView1.CurrentRow.Cells[0].Value?.ToString() ?? "";
ただし、列の順番が変わると取得対象も変わるため、実務では列名で指定する方が安全です。
15-5. DataGridViewの内容を保存するには?
DataGridViewの内容を保存するには、保存先に応じた処理が必要です。
CSVに保存する場合は、行と列をループして文字列を書き出します。
DBに保存する場合は、INSERT、UPDATE、DELETE文を実行します。
DataTableを使っている場合は、DataTableの内容を保存します。
Listを使っている場合は、Listの内容を保存します。
保存前には、編集中のセルを確定させておくと安全です。
C#dataGridView1.EndEdit();
DataGridViewは保存機能を自動で持っているわけではないため、保存処理は自分で実装する必要があります。
15-6. DataGridViewで大量データを扱うには?
大量データを扱う場合は、全件をDataGridViewに表示しないことが重要です。
検索条件を指定して必要なデータだけ取得する。
SQLのWHERE句で絞り込む。
ページングを使う。
VirtualModeを検討する。
表示する列を減らす。
自動列幅調整を控える。
DataGridViewは便利ですが、大量データをそのまま表示すると遅くなります。
実務では、表示件数を制限する設計にするのがおすすめです。
15-7. WPFでもDataGridViewは使える?
DataGridViewはWindowsフォームのコントロールです。
WPFで表データを表示する場合は、通常はWPFのDataGridを使います。
WindowsFormsHostを使えばWPF上にWindowsフォームのDataGridViewを表示することもできますが、WPFアプリではDataGridを使う方が自然です。
WindowsフォームアプリならDataGridView、WPFアプリならDataGrid、と考えるとよいでしょう。
まとめ
C# DataGridViewは、Windowsフォームアプリで表形式のデータを表示・編集するための非常に便利なコントロールです。
基本的な使い方は、列を追加してRows.Addで行を表示する方法と、DataTableやListをDataSourceに設定する方法に分かれます。
初心者が特につまずきやすいのは、DataSourceありとなしの違いです。
DataSourceなしの場合は、DataGridViewに直接行を追加・削除します。
DataSourceありの場合は、DataTableやBindingListなどの元データを操作します。
編集機能では、ReadOnly、CellValueChanged、CellValidating、DataErrorなどのプロパティやイベントを使います。
削除処理では、選択行の確認、IsNewRowの確認、確認ダイアログの表示を入れると安全です。
見た目を整えるには、列幅、ヘッダー名、フォント、文字位置、背景色、表示形式を設定します。
検索や絞り込みでは、少量データならセルのループ、DataTableならDataView.RowFilter、ListならLINQが便利です。
データベース連携では、SQL結果をDataTableに読み込み、DataGridViewのDataSourceに設定する流れが基本です。
C# DataGridViewを実務で使いこなすには、DataGridViewを単なる表ではなく、「表示」「編集」「データ管理」「保存処理」を分けて考えることが大切です。
この記事のサンプルコードをもとに、まずは表示、追加、編集、削除の基本操作から実装してみてください。

