Подтвердить что ты не робот

DataGridView: копирование в буфер обмена

У меня есть DataGridView в приложении .Net(V4 С# VS2010) и вы хотите скопировать все данные в буфер обмена одним нажатием кнопки. Нет проблем -

private void copyToClipboard()
{
    dataGridView1.SelectAll();
    DataObject dataObj = dataGridView1.GetClipboardContent();
    if (dataObj != null)
        Clipboard.SetDataObject(dataObj);
}

Проблема заключается в том, что у пользователя могут быть некоторые ячейки, строки и т.д., выбранные в DataGrid, и я действительно не хочу менять этот выбор. Вышеизложенное явно выбирает все. Я мог бы dataGridView1.ClearSelection(); в конце, который немного лучше, но все еще не достигает того, что требуется.

Я могу сохранить выбранные ячейки:

var mySelectedCells = dataGridView1.SelectedCells;

но как я могу вернуть выбранные ячейки в DataGrid после копии? Есть ли простой способ вернуть выбранную коллекцию ячеек в DataGrid? Возможно, есть лучший способ получить всю сетку, скопированную в буфер обмена, в первую очередь, не затрагивая выбранные ячейки?

4b9b3361

Ответ 1

Я предполагаю, что если вы просто хотели представить содержимое ячеек в виде текста и скопировать их в буфер обмена с разделителями табуляции, вы могли бы сделать что-то вроде:

    var newline = System.Environment.NewLine;
    var tab = "\t";
    var clipboard_string = "";

    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
         for (int i=0; i < row.Cells.Count; i++)
         {
              if(i == (row.Cells.Count - 1))
                   clipboard_string += row.Cells[i].Value + newline;
              else
                   clipboard_string += row.Cells[i].Value + tab;
         }
    }

    Clipboard.SetText(clipboard_string);

Результат кажется очень похожим на вывод GetClipboardContent(), но будьте осторожны для любых DataGridViewImageColumns или любого типа, который не является неявно строкой.

Изменить: Энтони прав, используйте StringBuilder, чтобы избежать выделения новой строки для каждой конкатенации. Новый код:

    var newline = System.Environment.NewLine;
    var tab = "\t";
    var clipboard_string = new StringBuilder();

    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
        for (int i = 0; i < row.Cells.Count; i++)
        {
            if (i == (row.Cells.Count - 1))
                clipboard_string.Append(row.Cells[i].Value + newline);
            else
                clipboard_string.Append(row.Cells[i].Value + tab);
        }
    }

    Clipboard.SetText(clipboard_string.ToString());

Ответ 2

Вот версия кода VB на С# с параметрами копирования заголовков и копирования только выбранных строк.

    private void CopyDataGridViewToClipboard(DataGridView dgv, bool includeHeaders = true, bool allRows = false) 
    {
        // copies the contents of selected/all rows in a data grid view control to clipboard with optional headers
        try
        {
            string s = "";
            DataGridViewColumn oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
            if (includeHeaders)
            {                   
                do
                {
                    s = s + oCurrentCol.HeaderText + "\t";
                    oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None);
                }
                while (oCurrentCol != null);
                s = s.Substring(0, s.Length - 1);
                s = s + Environment.NewLine;    //Get rows
            }
            foreach (DataGridViewRow row in dgv.Rows)
            {
                oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible);

                if (row.Selected || allRows)
                {
                    do
                    {
                        if (row.Cells[oCurrentCol.Index].Value != null) s = s + row.Cells[oCurrentCol.Index].Value.ToString();
                        s = s + "\t";
                        oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None);
                    }
                    while (oCurrentCol != null);
                    s = s.Substring(0, s.Length - 1);
                    s = s + Environment.NewLine;
                }                                      
            }
            Clipboard.SetText(s);
        }
        catch (Exception ex)
        {
            toolStripStatusLabel2.Text = @"Error: " + ex.Message;
        }
    }

Ответ 3

Я думаю, что ниже метод точно сделает то, что вы хотите. Просто вызовите этот метод с именем DataGridView при событии нажатия кнопки.

Private Sub CopyDataGridViewToClipboard(ByRef dgv As DataGridView)
    Try
        Dim s As String = ""
        Dim oCurrentCol As DataGridViewColumn    'Get header
        oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)
        Do
            s &= oCurrentCol.HeaderText & Chr(Keys.Tab)
            oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, _
               DataGridViewElementStates.Visible, DataGridViewElementStates.None)
        Loop Until oCurrentCol Is Nothing
        s = s.Substring(0, s.Length - 1)
        s &= Environment.NewLine    'Get rows
        For Each row As DataGridViewRow In dgv.Rows
            oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)
            Do
                If row.Cells(oCurrentCol.Index).Value IsNot Nothing Then
                    s &= row.Cells(oCurrentCol.Index).Value.ToString
                End If
                s &= Chr(Keys.Tab)
                oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, _
                      DataGridViewElementStates.Visible, DataGridViewElementStates.None)
            Loop Until oCurrentCol Is Nothing
            s = s.Substring(0, s.Length - 1)
            s &= Environment.NewLine
        Next    'Put to clipboard
        Dim o As New DataObject
        o.SetText(s)
        Clipboard.SetDataObject(o, True)

    Catch ex As Exception
        ShowError(ex, Me)
    End Try
End Sub

Ответ 4

Столбцы DataGridView могут быть видимыми/невидимыми, а также могут отображаться в том порядке, в котором они были созданы. Этот код заботится о обоих:

public static void CopyGridViewToClipboard(DataGridView gvCopy)
    {
        if (gvCopy == null) return;
        StringBuilder s = new StringBuilder();

        int offset = gvCopy.ColumnHeadersVisible ? 1 : 0;
        int visibleColumnsCount = 0;

        //count visible columns and build mapping between each column and it display position
        Dictionary<int, int> indexMapping = new Dictionary<int, int>();
        int currIndex = 0;
        int lastFoundMinDisplayIndex = -1;
        for (int j = 0; j < gvCopy.ColumnCount; j++)
        {
            //find min DisplayIndex >= currIndex where column is visible
            int minDisplayIndex = 100000;
            int minDisplayIndexColumn = 100000;
            for (int k = 0; k < gvCopy.ColumnCount; k++)
            {
                if ((gvCopy.Columns[k].Visible) && (gvCopy.Columns[k].DisplayIndex >= currIndex) && (gvCopy.Columns[k].DisplayIndex > lastFoundMinDisplayIndex))
                {
                    if (gvCopy.Columns[k].DisplayIndex < minDisplayIndex)
                    {
                        minDisplayIndex = gvCopy.Columns[k].DisplayIndex;
                        minDisplayIndexColumn = k;
                    }
                }
            }

            if (minDisplayIndex == 100000) break;

            indexMapping.Add(minDisplayIndexColumn, currIndex);

            lastFoundMinDisplayIndex = minDisplayIndex;
            currIndex++;
        }
        visibleColumnsCount = currIndex;

        //put data in temp array -- required to position columns in display order
        string[,] data = new string[gvCopy.RowCount + offset, visibleColumnsCount];

        if (gvCopy.ColumnHeadersVisible)
        {
            for (int j = 0; j < gvCopy.ColumnCount; j++)
            {
                if (gvCopy.Columns[j].Visible)
                {
                    data[0, indexMapping[j]] = gvCopy.Columns[j].HeaderText;
                }
            }
        }

        for (int i = 0; i < gvCopy.RowCount; i++)
        {
            for (int j = 0; j < gvCopy.ColumnCount; j++)
            {
                if (gvCopy.Columns[j].Visible)
                {
                    data[i + offset, indexMapping[j]] = gvCopy[j, i].FormattedValue.ToString();
                }
            }
        }

        //copy data
        for (int i = 0; i < gvCopy.RowCount + offset; i++)
        {
            for (int j = 0; j < visibleColumnsCount; j++)
            {
                s.Append(data[i, j]);

                s.Append("\t");
            }
            s.Append("\r\n");
        }
        Clipboard.SetDataObject(s.ToString());
    }

Ответ 5

Вы должны изменить свойство множественного выбора DataGridView. Вот код:

private void copyToClipboard()
{
  dataGridView1.MultiSelect = True;
  dataGridView1.SelectAll();
  DataObject dataObj = dataGridView1.GetClipboardContent();
  if (dataObj != null)
  Clipboard.SetDataObject(dataObj);
}