DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DOBON.NET

DataGridViewで選択されたセルをクリップボードにコピーできるようにする

注意:DataGridViewコントロールは、.NET Framework 2.0で新しく追加されました。

DataGridView.ClipboardCopyModeプロパティがDataGridViewClipboardCopyMode.Disable以外のときは、「Ctrl + C」キーを押すことにより、選択されたセルがクリップボードにコピーされるようになります。形式は、Text、UnicodeText、Html、CommaSeparatedValueとなるため、Excelなどへのペーストも可能です。

ClipboardCopyModeによって、ヘッダーをコピーするかどうかを決めることができます。EnableAlwaysIncludeHeaderTextではヘッダーもコピーされ、EnableWithoutHeaderTextではコピーされません。既定値であるEnableWithAutoHeaderTextでは、ヘッダーが選択されている場合にコピーされます。

[VB.NET]
'ヘッダーをコピーしないようにする
DataGridView1.ClipboardCopyMode = _
    DataGridViewClipboardCopyMode.EnableWithoutHeaderText
[C#]
//ヘッダーをコピーしないようにする
DataGridView1.ClipboardCopyMode =
    DataGridViewClipboardCopyMode.EnableWithoutHeaderText;

プログラムにより、コピーする

ボタンをクリックした時や、メニューで選択した時にクリップボードにコピーするには、DataGridView.GetClipboardContentメソッドでDataObjectオブジェクトを取得して、これをパラメータとしてClipboard.SetDataObjectメソッドを呼び出します。

以下に具体的なコードを示します。

[VB.NET]
'選択されたセルをクリップボードにコピーする
Clipboard.SetDataObject(DataGridView1.GetClipboardContent())
[C#]
//選択されたセルをクリップボードにコピーする
Clipboard.SetDataObject(DataGridView1.GetClipboardContent());

DataGridViewにペーストする

このようにクリップボードにコピーするのは簡単ですが、DataGridViewにペーストする(貼り付ける)のは大変です。「Ctrl + V」キーでペーストすることもできませんし、このような機能のメソッドが用意されている訳でもありません。つまり、自分でそのようなコードを書くしかありません。

以下に、ペーストを行うごく簡単な例を示します。この例では、コピーした行を現在のセルのある行以降にペーストするものです。行を挿入するのではなく、現在のセルの値を上書きしています(データがバインドされていると挿入できないため)。また、クリップボードにあるデータには列と行ヘッダーが含まれていると決め付けていますし、データ型も全く調べていません。

[VB.NET]
'現在のセルのある行から下にペーストする
If DataGridView1.CurrentCell Is Nothing Then
    Return
End If
Dim insertRowIndex As Integer = DataGridView1.CurrentCell.RowIndex

'クリップボードの内容を取得して、行で分ける
Dim pasteText As String = Clipboard.GetText()
If String.IsNullOrEmpty(pasteText) Then
    Return
End If
pasteText = pasteText.Replace(vbCrLf, vbLf)
pasteText = pasteText.Replace(vbCr, vbLf)
pasteText.TrimEnd(New Char() {vbLf})
Dim lines As String() = pasteText.Split(vbLf)

Dim isHeader As Boolean = True
For Each line As String In lines
    '列ヘッダーならば飛ばす
    If isHeader Then
        isHeader = False
    Else
        'タブで分割
        Dim vals As String() = line.Split(ControlChars.Tab)
        '列数が合っているか調べる
        If vals.Length - 1 <> DataGridView1.ColumnCount Then
            Throw New ApplicationException("列数が違います。")
        End If
        Dim row As DataGridViewRow = DataGridView1.Rows(insertRowIndex)
        'ヘッダーを設定
        row.HeaderCell.Value = vals(0)
        '各セルの値を設定
        Dim i As Integer
        For i = 0 To row.Cells.Count - 1
            row.Cells(i).Value = vals((i + 1))
        Next i

        '次の行へ
        insertRowIndex += 1
    End If
Next line
[C#]
//現在のセルのある行から下にペーストする
if (DataGridView1.CurrentCell == null)
    return;
int insertRowIndex = DataGridView1.CurrentCell.RowIndex;

//クリップボードの内容を取得して、行で分ける
string pasteText = Clipboard.GetText();
if (string.IsNullOrEmpty(pasteText))
    return;
pasteText = pasteText.Replace("\r\n", "\n");
pasteText = pasteText.Replace('\r', '\n');
pasteText.TrimEnd(new char[] { '\n' });
string[] lines = pasteText.Split('\n');

bool isHeader = true;
foreach (string line in lines)
{
    //列ヘッダーならば飛ばす
    if (isHeader)
    {
        isHeader = false;
        continue;
    }

    //タブで分割
    string[] vals = line.Split('\t');
    //列数が合っているか調べる
    if (vals.Length - 1 != DataGridView1.ColumnCount)
        throw new ApplicationException("列数が違います。");
    DataGridViewRow row = DataGridView1.Rows[insertRowIndex];
    //ヘッダーを設定
    row.HeaderCell.Value = vals[0];
    //各セルの値を設定
    for (int i = 0; i < row.Cells.Count; i++)
    {
        row.Cells[i].Value = vals[i + 1];
    }

    //次の行へ
    insertRowIndex++;
}