C# WinForms DataGridViewの実用的な操作ガイド

行の動的追加とカスタマイズ

新しい行をプログラムで追加するには、いくつかのアプローチがあります。単純な値のセットだけでなく、コンボボックスなどの特定のセル型を持つ行を作成する場合は、行オブジェクトを明示的にインスタンス化する方法が適しています。

// シンプルな追加方法
var targetGrid = dataGridView1;
int newRowIdx = targetGrid.Rows.Add();
targetGrid.Rows[newRowIdx].Cells[0].Value = "データA";
targetGrid.Rows[newRowIdx].Cells[1].Value = "データB";

// セル型をカスタマイズする追加方法
var customRow = new DataGridViewRow();
var textCell = new DataGridViewTextBoxCell { Value = "テキスト" };
customRow.Cells.Add(textCell);

var comboCell = new DataGridViewComboBoxCell();
comboCell.Items.AddRange("項目1", "項目2");
customRow.Cells.Add(comboCell);

dataGridView1.Rows.Add(customRow);

ヘッダー設定の変更

列ヘッダーや行ヘッダーのテキストは、特定のプロパティを通じて簡単に変更可能です。

// 列ヘッダーの設定
dataGridView1.Columns[0].HeaderText = "ID";
dataGridView1.Columns[0].HeaderCell.Value = "識別子";

// 行ヘッダーの設定
dataGridView1.Rows[0].HeaderCell.Value = "行1";

// 左上隅のヘッダーセル
dataGridView1.TopLeftHeaderCell.Value = "一覧";

アクティブセルの制御とナビゲーション

現在フォーカスがあるセル(アクティブセル)はCurrentCellプロパティで管理します。このプロパティを操作することで、選択位置をプログラムから移動させることができます。

// アクティブセルの情報取得
var activeCell = dataGridView1.CurrentCell;
if (activeCell != null)
{
    var val = activeCell.Value;
    int colIdx = activeCell.ColumnIndex;
    int rowIdx = activeCell.RowIndex;
}

// 選択位置の移動(上下のナビゲーション例)
private void MoveSelection(int direction)
{
    if (dataGridView1.CurrentRow == null) return;
    
    int currentRow = dataGridView1.CurrentRow.Index;
    int targetRow = currentRow + direction;

    // 循環移動のロジック
    if (targetRow >= dataGridView1.RowCount) targetRow = 0;
    if (targetRow < 0) targetRow = dataGridView1.RowCount - 1;

    dataGridView1.CurrentCell = dataGridView1[0, targetRow];
}

インデクサを使用する際の注意点として、dataGridView[columnIndex, rowIndex] の順序(列、行)を守る必要があります。

編集の制限(読み取り専用)

コントロール全体、特定の列、行、または個々のセルに対して編集を禁止する設定が可能です。

// 全体を読み取り専用に
dataGridView1.ReadOnly = true;

// 特定の列や行のみ制限
dataGridView1.Columns[1].ReadOnly = true;
dataGridView1.Rows[2].ReadOnly = true;

// 特定のセルのみ制限
dataGridView1[0, 0].ReadOnly = true;

// プログラムによる編集のみ許可
dataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically;

// イベントを使用した編集のキャンセル例
private void OnCellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
    var grid = (DataGridView)sender;
    // 条件に応じて編集を禁止
    if (grid.Columns[e.ColumnIndex].Name == "ColA" && e.RowIndex % 2 == 0)
    {
        e.Cancel = true;
    }
}

行の表示・非表示と削除

ユーザーインターフェース上での行の追加や削除を制御し、データの整合性を保つための設定です。

// 新規行の追加をUIから禁止
dataGridView1.AllowUserToAddRows = false;

// 行の削除をUIから禁止
dataGridView1.AllowUserToDeleteRows = false;

// 削除時の確認ダイアログ表示
private void OnUserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
    var confirm = MessageBox.Show("削除してもよろしいですか?", "確認", MessageBoxButtons.OKCancel);
    if (confirm != DialogResult.OK)
    {
        e.Cancel = true;
    }
}

// 特定の行を非表示にする
dataGridView1.Rows[0].Visible = false;
dataGridView1.Columns[0].Visible = false;

サイズ変更の自動化と制御

内容に応じて幅や高さを自動調整する機能は便利ですが、データ量が多い場合はパフォーマンスに影響するため、モードの選択が重要です。

// すべてのセルに基づいて自動調整(重い)
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

// 表示中のセルのみに基づいて調整(軽量)
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;

// 特定の列のモードを変更
dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;

// ユーザーによるサイズ変更の禁止
dataGridView1.AllowUserToResizeColumns = false;
dataGridView1.AllowUserToResizeRows = false;

// 最小幅・最小高の設定
dataGridView1.Columns[0].MinimumWidth = 100;
dataGridView1.Rows[0].MinimumHeight = 40;

列の固定と順序変更

スクロール時に特定の列を画面左側に固定しておく(フリーズ)機能や、列の表示順序を動的に変更する方法です。

 // 2列目までを固定(インデックス1まで)
if (dataGridView1.ColumnCount > 1)
{
    dataGridView1.Columns[1].Frozen = true;
}

// 列順序の変更許可
dataGridView1.AllowUserToOrderColumns = true;

// プログラムによる列順序の変更
dataGridView1.Columns["ColName"].DisplayIndex = 0;

クリップボードとの連携

標準機能でコピーはサポートされていますが、貼り付け(ペースト)は独自に実装する必要があります。以下はタブ区切りテキストを貼り付ける実装例です。

// 貼り付け処理の実装例
if (dataGridView1.CurrentCell == null) return;

string clipboardText = Clipboard.GetText();
if (string.IsNullOrWhiteSpace(clipboardText)) return;

var rowsData = clipboardText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int startRow = dataGridView1.CurrentCell.RowIndex;

foreach (var rowText in rowsData)
{
    if (startRow >= dataGridView1.RowCount) break;

    var cellValues = rowText.Split('\t');
    for (int i = 0; i < Math.Min(cellValues.Length, dataGridView1.ColumnCount); i++)
    {
        dataGridView1[i, startRow].Value = cellValues[i];
    }
    startRow++;
}

セルの書式設定と入力検証

CellFormattingイベントを使用して表示値を整形したり、CellValidatingイベントで入力値の妥当性をチェックしたりします。

// 表示時の書式設定(例:大文字に変換)
private void OnCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (dataGridView1.Columns[e.ColumnIndex].Name == "Code" && e.Value is string txt)
    {
        e.Value = txt.ToUpper();
        e.FormattingApplied = true;
    }
}

// 入力検証
private void OnCellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (dataGridView1.Columns[e.ColumnIndex].Name == "Email")
    {
        if (e.FormattedValue.ToString().IndexOf("@") < 0)
        {
            e.Cancel = true;
            dataGridView1.Rows[e.RowIndex].ErrorText = "無効なメールアドレス形式です";
        }
    }
}

行ヘッダーへの行番号表示

DataGridViewに行番号を表示するには、RowPostPaintイベントを利用して描画処理を追加します。

private void OnRowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
    var grid = sender as DataGridView;
    var rowNumber = (e.RowIndex + 1).ToString();
    
    var headerFont = new Font("Segoe UI", 9);
    var headerBounds = new Rectangle(e.RowBounds.Location.X, 
                                     e.RowBounds.Location.Y, 
                                     grid.RowHeadersWidth - 4, 
                                     e.RowBounds.Height);
    
    TextRenderer.DrawText(e.Graphics, rowNumber, headerFont, 
                          headerBounds, 
                          grid.RowHeadersDefaultCellStyle.ForeColor, 
                          TextFormatFlags.Right | TextFormatFlags.VerticalCenter);
}

セルの結合描画(カスタムペイント)

DataGridViewは標準でセル結合をサポートしていませんが、CellPaintingイベントで背景や境界線を自描画することで、結合されているように見せることが可能です。以下は、同じ値を持つ縦方向の隣接セルを視覚的に結合するロジックの簡略版です。

private void OnCellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    // 描画対象の列(例:"Category"列)
    if (e.ColumnIndex >= 0 && dataGridView1.Columns[e.ColumnIndex].Name == "Category" && e.RowIndex >= 0)
    {
        // 1行目以外で、上のセルと値が同じ場合
        if (e.RowIndex > 0 && 
            e.Value != null && 
            e.Value.Equals(dataGridView1[e.ColumnIndex, e.RowIndex - 1].Value))
        {
            // 背景を塗りつぶし(標準描画をキャンセル)
            e.Graphics.FillRectangle(new SolidBrush(e.CellStyle.BackColor), e.CellBounds);
            
            // テキストは描画せず、下の境界線も消すことで結合に見せる
            e.Handled = true;
        }
        else
        {
            // 値が異なる場合、または最終行の場合は通常描画(必要に応じて下線を引く)
            e.Paint(e.CellBounds, DataGridViewPaintParts.All);
            
            // 下に同じ値のセルがある場合は下枠を消す
            if (e.RowIndex < dataGridView1.RowCount - 1 && 
                e.Value != null && 
                e.Value.Equals(dataGridView1[e.ColumnIndex, e.RowIndex + 1].Value))
            {
                 // 下線部分を背景色で上書き
                 var rect = new Rectangle(e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Width, 1);
                 e.Graphics.FillRectangle(new SolidBrush(e.CellStyle.BackColor), rect);
            }
            e.Handled = true;
        }
    }
}

タグ: C# WinForms DataGridView .NET UI

6月25日 16:30 投稿