【C#】DataGridViewで行コピーペーストを実装する

f:id:ktts:20200331234605p:plain

C#のDataGridViewで行コピペ機能が欲しかったので調査結果をノートします。

参考サイト
stackoverflow.com

C#の場合】
下記クラスを作成します

using System.Windows.Forms;

public class ClipboardUtils
{
    public static void OnDataGridViewPaste(object grid, KeyEventArgs e)
    {
        if ((e.Shift && e.KeyCode == Keys.Insert) || (e.Control && e.KeyCode == Keys.V))
        {
            PasteTSV((DataGridView)grid);
        }
    }

    public static void PasteTSV(DataGridView grid)
    {
        char[] rowSplitter = { '\r', '\n' };
        char[] columnSplitter = { '\t' };

        // クリップボードからテキストを取得する
        IDataObject dataInClipboard = Clipboard.GetDataObject();
        string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);

        // グリッドで分割する
        string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);

        // ペースト先のセル番地を取得する
        int r = grid.SelectedCells[0].RowIndex;
        int c = grid.SelectedCells[0].ColumnIndex;

        // コピペで行数が不足している場合は、行追加する
        if (grid.Rows.Count - (grid.AllowUserToAddRows ? 1 : 0) < (r + rowsInClipboard.Length))
        {
            grid.Rows.Add(r + rowsInClipboard.Length - grid.Rows.Count + (grid.AllowUserToAddRows ? 1 : 0));
        }

        // コピー行を列挙する
        for (int iRow = 0; iRow < rowsInClipboard.Length; iRow++)
        {
            // Split row into cell values
            List<string> valuesInRow = rowsInClipboard[iRow].Split(columnSplitter).ToList();

            // コピーしている列数がグリッドの列数を超える場合は、先頭から削除する(RowHeadersVisible表示時)
            while (valuesInRow.Count > grid.ColumnCount)
            {
                valuesInRow.RemoveAt(0);
            }

            // コピーセルを列挙する
            for (int iCol = 0; iCol < valuesInRow.Count; iCol++)
            {
                // グリッドの列数を超えない場合に、対応するセルに値を入力する
                if (grid.ColumnCount - 1 >= c + iCol)
                {
                    DataGridViewCell cell = grid.Rows[r + iRow].Cells[c + iCol];

                    if (!cell.ReadOnly)
                    {
                        cell.Value = valuesInRow[iCol];
                    }
                }
            }
        }
    }
}

DataGridViewには下記イベントを追加します

private void DataGridView1_KeyUp(object sender, KeyEventArgs e)
{
    ClipboardUtils.OnDataGridViewPaste(sender, e);
}