概要
Windows FormsのコントロールのひとつであるDataGridViewについて、少し整理したく勉強を兼ねて簡単にまとめてみました。
主にDataTableクラスを使用する方法についてまとめています。
目次
- DataGridViewとは
- DataTableとは
- DataGridViewのクラス構成図
- DataGridViewの列や行の追加方法
- 列追加してデータ表示
- 行 (データ) の追加
- 行 (データ) の編集
- 行 (データ) の削除
DataGridViewとは
Windows FormsのUIコントロールで、表形式でデータを表示・編集するためのビューです。データはDataSourceプロパティで受け取ります。DataGridViewでデータを表示するときは、一般的にはDataTableクラスというものが使用されます (DataTableクラスを使用する方法以外にも、データを表示する方法はいくつかあります)。
DataTableとは
メモリ上のデータ構造で、行と列を持つ「データ保持用」のクラスです。データベースのテーブルに似ていますが、UIとは無関係です。
DataTableのデータを目視で確認したい場合はDataGridViewを使用する以外にも、CSVなどの外部ファイルに出力するという方法があります。
DataGridViewのクラス構成図
DataGridViewは様々なクラスから構成されています。この中のDataSourceにDataTableを入れると、DataGridView上に表示されます。
DataGridView
├─ Columns : DataGridViewColumnCollection
│ ├─ TextBoxColumn / CheckBoxColumn / ComboBoxColumn / ButtonColumn / ...
│ └─ DataPropertyName
├─ Rows : DataGridViewRowCollection
├─ DefaultCellStyle / ColumnHeadersDefaultCellStyle / ...
└─ DataSource
DataGridViewの列や行の追加方法
単に列や行を追加するのでも、一つではなく様々な方法があります。
列追加の方法
- DataGridViewのColumnsの
Add()を使用 - DataTableクラスの列定義を流用
行追加の方法
-
dataGridView.Rows.Add()を使用 - DataTableクラスの
DataTable.Rows.Add(...)またはNewRow()を使用してDataSourceにバインド
以下、サンプルコードです。
列追加してデータ表示
DataTableをバインドする場合
private DataTable _table = new DataTable();
private void SetupGrid_DataTable_Auto()
{
// DataTableの列を定義
_table.Columns.Add("Id", typeof(int));
_table.Columns.Add("Name", typeof(string));
_table.Columns.Add("IsActive", typeof(bool));
// データ追加
_table.Rows.Add(1, "田中", true);
_table.Rows.Add(2, "佐藤", false);
_table.Rows.Add(3, "鈴木", true);
// DataGridViewの設定
dataGridView.AutoGenerateColumns = true;
dataGridView.DataSource = _table;
}
ポイント
AutoGenerateColumnsについて
AutoGenerateColumnsがtrueだと、DataGridViewがDataTableの列定義を読み取り、自動的にDataGridViewの列 (DataGridViewColumn) を生成してくれます。AutoGenerateColumnsの規定値はtrueですが、falseにすると、そもそも列定義が読み取れず、DataGridView内に表が表示されません。falseにした場合は、DataGridView.Columnsに手動で列を追加し、各列のDataPropertyNameをDataTableの列名に一致させれば表示されます。
DataGridViewの列を手動で定義する場合
private DataTable _table = new DataTable();
private void SetupGrid_ManualColumns()
{
// DataTable にデータ列を定義(列名は DataPropertyName と一致させる)
_table.Columns.Add("Id", typeof(int));
_table.Columns.Add("Name", typeof(string));
_table.Columns.Add("IsActive", typeof(bool));
// DataGridView の列を手動で定義
dataGridView.AutoGenerateColumns = false;
dataGridView.Columns.Clear();
// ID 列を手動設定
var colId = new DataGridViewTextBoxColumn
{
Name = "colId", // DataGridView 内での名前
HeaderText = "id", // 表示名
DataPropertyName = "Id", // DataTable の列名と一致
Width = 60,
ValueType = typeof(int)
};
dataGridView.Columns.Add(colId);
// 名前列を手動設定
var colName = new DataGridViewTextBoxColumn
{
Name = "colName",
HeaderText = "Name",
DataPropertyName = "Name",
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
};
dataGridView.Columns.Add(colName);
// チェックボックス列を手動設定
var colActive = new DataGridViewCheckBoxColumn
{
Name = "colActive",
HeaderText = "IsActive",
DataPropertyName = "IsActive",
Width = 70
};
dataGridView.Columns.Add(colActive);
// DataGridView に DataTable をバインド
dataGridView.DataSource = _table;
// データを追加(DataTable 側)
_table.Rows.Add(1, "田中", true);
_table.Rows.Add(2, "佐藤", false);
_table.Rows.Add(3, "鈴木", true);
}
ポイント
列追加について
列はDataTableではなくDataGridViewのColumnsから作成していますが、それでもDataTableの列は追加しています。これは、DataTableは列を定義してからでないと行に値を入れることはできない仕組みになっているからです。
列をまったく定義していないDataTableに値ありの行を追加することはできません。
列幅等について
DataGridViewで列を定義する場合は、上記のように列幅等細かなところも定義できます。DataTableの列は、列幅等UIに関する定義はできません。これは、DataTableが純粋にデータ構造を表すクラスで、UIの概念がないためです。DataGridViewはUIコントロールなので、UIに関する定義も可能です。
行 (データ) の追加
DataTableをバインドする場合
// データはすでに入っている前提
private DataTable _table = new DataTable();
private void AddRow_DataTable()
{
// 2行データを追加する
// 方法1:値をそのまま渡す
_table.Rows.Add(4, "高橋", true);
// 方法2:NewRow() で列名指定代入
var r = _table.NewRow(); // 空の DataRow を生成
r["Id"] = 5; // 列名を指定してアクセス
r["Name"] = "中村";
r["IsActive"] = false;
_table.Rows.Add(r); // テーブルに追加
}
ポイント
方法1について
この方法の場合、加えるデータの並びがテーブルの列順と一致していないと例外になったり、型変換に失敗することがあります。列が多い場合は方法2のNewRow()の方法が安全です。
DataGridViewに直接行を追加する場合
// 列はすでに DataGridView 側で定義済みとする
private void AddRow_Unbound()
{
int rowIndex = dataGridView.Rows.Add();
var row = dataGridView.Rows[rowIndex];
row.Cells["colId"].Value = 4;
row.Cells["colName"].Value = "高橋";
row.Cells["colActive"].Value = true;
}
ポイント
rowIndexについて
rowIndexには追加された行のインデックスが入ってきます。このインデックスからDataGridViewの新しい行オブジェクトを取得し、列名指定で値を追加しています。
行 (データ) の編集
DataTableをバインドする場合
// データはすでに入っている前提
private DataTable _table = new DataTable();
private void EditRow_ById_DataTable(int id, string newName, bool newActive)
{
var row = _table.Rows.Find(id); // ← PrimaryKey 設定済みが前提 (_table.PrimaryKey = new[] { _table.Columns["Id"] };のような形)
if (row != null)
{
row["Name"] = newName;
row["IsActive"] = newActive;
}
}
DataGridViewのRowsコレクションから編集する場合
private void EditRow_ById_Unbound(int id, string newName, bool newActive)
{
foreach (DataGridViewRow row in dataGridView.Rows)
{
if (!row.IsNewRow && Convert.ToInt32(row.Cells["colId"].Value) == id)
{
row.Cells["colName"].Value = newName;
row.Cells["colActive"].Value = newActive;
break; // 最初に見つかった1行だけ編集
}
}
}
ポイント
!row.IsNewRowについて
この条件で、で末尾の「新規入力用行(*)」をスキップしています。
行 (データ) の削除
DataTableをバインドする場合
// データはすでに入っている前提
private DataTable _table = new DataTable();
private void DeleteRow_ById_DataTable(int id)
{
var row = _table.Rows.Find(id);
if (row != null)
{
_table.Rows.Remove(row);
}
}
DataGridViewから直接削除する場合
private void DeleteRow_ById_Unbound(int id)
{
for (int i = dataGridView.Rows.Count - 1; i >= 0; i--)
{
var row = dataGridView.Rows[i];
if (!row.IsNewRow && row.Cells["id"].Value != null &&
Convert.ToInt32(row.Cells["id"].Value) == id)
{
dataGridView.Rows.RemoveAt(i);
break;
}
}
}
補足
例えば、SQLを使用してDBに対して値変更や行追加を行い、その後SELECT文で得たDataTableクラスのデータをDataGridViewに表示するような場合は、得たDataTableクラスをDataGridViewのDataSourceに入れるだけで更新して再表示ができます。
終わりに
本稿はDataTableメインでのDataGridViewの操作 (追加・編集・削除) の最小実装をまとめました。実際の運用ではSQLを用いてデータの編集や追加を行うケースが多いかと思いますが、ここで紹介する内容は最低限の知識として理解しておくと役立つと思われます。
