вторник, 19 января 2010 г.

DataGridView + вставка из буфера обмена

Если вы еще с этим не сталкивались - то я вас обрадую: стандартный DataGridView в буфер обмена данные копировать умеет, а вот обратно - нет :( Однако, решение данной проблемы есть.

- В свойствах формы прописать свойство keypreview равным true
- В KeyUp добавить следующий обработчик событий:

private void form1_KeyUp(object sender, KeyEventArgs e)
{
   //if user clicked Shift+Ins or Ctrl+V (paste from clipboard)
   if ((e.Shift && e.KeyCode == Keys.Insert) || (e.Control && e.KeyCode == Keys.V))
   {
      char[] rowSplitter = { '\r', '\n' };
      char[] columnSplitter = { '\t' };

      //get the text from clipboard
      IDataObject dataInClipboard = Clipboard.GetDataObject();
      string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);

      //split it into lines
      string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);

      //get the row and column of selected cell in grid
      int r = grid.SelectedCells[0].RowIndex;
      int c = grid.SelectedCells[0].ColumnIndex;

      //add rows into grid to fit clipboard lines
      if (grid.Rows.Count < (r + rowsInClipboard.Length))
        grid.Rows.Add(r + rowsInClipboard.Length - grid.Rows.Count);

      // loop through the lines, split them into cells and place the values in the corresponding cell.
      for (int iRow = 0; iRow < rowsInClipboard.Length; iRow++)
      {
        //split row into cell values
        string[] valuesInRow = rowsInClipboard[iRow].Split(columnSplitter);

        //cycle through cell values
        for (int iCol = 0; iCol < valuesInRow.Length; iCol++)
        {
          //assign cell value, only if it within columns of the grid
          if (grid.ColumnCount - 1 >= c + iCol)
            grid.Rows[r + iRow].Cells[c + iCol].Value = valuesInRow[iCol];
        }
      }
   }
}

Обращаю внимание, что valuesInRow[iCol] необходимо привести к нужному типу данных, а то потом будут проблемы.

P.S.: Оригинал можно почитать здесь

7 комментариев:

  1. Добрый день!
    Спасибо за простое и красивое решение.
    Есть пара дополнений:
    1. На форме может быть несколько DataGridView - а Вы в коде задали жестко один конкретный. Вот вариант реализации поиска DataGridView, который вызвал событие (поместить в самом начале функции):
    //Find the source of the event
    Form form = (Form)sender;
    DataGridView grid = null;
    for (int i = 0; i < form.Controls.Count; i++)
    {
    if (form.Controls[i].ContainsFocus)
    {
    if (form.Controls[i].GetType().ToString() != "System.Windows.Forms.DataGridView")
    return;
    grid = (DataGridView)form.Controls[i];
    break;
    }
    }
    2. Если вы вошли в режим редактирования в одной из ячеек DataGridView и там выполнили Ctrl-V, то нужно обновить данную ячейку, иначе там мусор. В самый конец Вашей функции добавить строчку:
    grid.RefreshEdit(); //Refresh the edited cell

    Еще раз спасибо!

    ОтветитьУдалить
  2. А как быть с много строчной вставкой?

    ОтветитьУдалить
    Ответы
    1. мне надо было только два столбца дополнять, но под универсальный случай допилить не проблематично
      private void pasteClipboardtoDG()
      {
      if (Clipboard.ContainsText(TextDataFormat.Text))//сли в Clipboard есть текст копируем его в лист
      {
      string[] tabvalfld = Clipboard.GetText().Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); //Regex.Split(string,"xx")
      int i = 0;
      foreach (var s in tabvalfld)
      {
      string[] tabvalfld1 = s.Split('\t');
      if (tabvalfld1[0] != null)
      {
      dataGridView1.Rows.Add(1);
      dataGridView1.Rows[i].Cells[0].Value = tabvalfld1[0];
      if (tabvalfld1.Length > 1 && tabvalfld1[1] != null)
      {
      dataGridView1.Rows[i].Cells[1].Value = tabvalfld1[1];
      }
      i++;
      }

      }
      }
      else
      {
      MessageBox.Show("No data in Clipboard", "SDF");
      }
      }

      Удалить
  3. Ну... Тут, наверное, придется исходный текст из буфера обмена резать как-то по другому. Приведенный код считает что новая строка в тексте - это новая строка в датагриде.

    ОтветитьУдалить
  4. ваша слчайно найденная запись здорово помогла мне в работе.
    спасибо =)

    ОтветитьУдалить
  5. хз конечно, после появление у меня такой задачи я пару минут по гуглил, нашел данный пост, мне показалось это сложным и нашел другой, вернее сам додумал, ниже код (работает на VB 2010)

    DataGridView1.CurrentCell.Value = My.Computer.Clipboard.GetText()

    ОтветитьУдалить