Domanda

Assume that I have a DataGridView which is populated by a number of different strings (different length, numbers and plain text) in Cells.

Want I want to do is to copy and paste these strings, which could be any selection of Cells.

My approach to copy is:

if (e.Control && e.KeyCode == Keys.C)
{
    // copy
    DataGridViewSelectedCellCollection tmpCells = this.MyDataGridView.SelectedCells;
    Clipboard.SetDataObject(tmpCells);
 }

Which is working properly.

My approach to paste is:

if (e.Control && e.KeyCode == Keys.V)
{
    // paste
    IDataObject dataInClipboard = Clipboard.GetDataObject();
    string stringInClipboard = (string)dataInClipboard.GetData(DataFormats.Text);
    char[] rowSplitter = { '\r', '\n' };
    char[] columnSplitter = { '\t' };
    string[] rowsInClipboard = stringInClipboard.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);

    int r1 = this.MyDataGridView.SelectedCells[0].RowIndex;
    int c1 = this.MyDataGridView.SelectedCells[0].ColumnIndex;
    int r2 = this.MyDataGridView.SelectedCells[this.MyDataGridView.SelectedCells.Count-1].RowIndex;
    int c2 = this.MyDataGridView.SelectedCells[this.MyDataGridView.SelectedCells.Count-1].ColumnIndex;

    int r = Math.Min(r1, r2);   // Do not care if selection was taken by drag mouse up or down, always start from min
    int c = Math.Min(c1, c2);   // Do not care if selection was taken by drag mouse left or right, always start from min

    for (int iRow = 0; iRow < rowsInClipboard.Length; ++iRow )
    {
        string[] valuesInRow = rowsInClipboard[iRow].Split(columnSplitter);

        for (int iCol = 0; iCol < valuesInRow.Length; ++iCol )
        {
            if (this.MyDataGridView.ColumnCount-1 >= c + iCol)
            {

                DataGridViewCell DGVC = (this.MyDataGridView.Rows[r + iRow].Cells[c + iCol]);

                DGVC.Value = valuesInRow[iCol];

             }
          }
     }
  }
}

Which works fine UNLESS the string itself DOES NOT contain any delimiter I specified with rowSplitter and columnSplitter. But this unfortunately is the case very often. It then separates the string and expands it to the next cell.

Example:

Cell[n] = {"This string contains a new line delimiter \n but should use only one cell."}

Will be pasted to:

Cell[n] = {"This string contains a new line delimiter"}; 
Cell[n+1] = {"but should use only one cell."}

So my question is: is it possible to restore the DataGridViewSelectedCellCollection as it was copied to the clipboard before? Just casting from object to DataGridViewSelectedCellCollection will not work:

DataGridViewSelectedCellCollection DGSCC = (DataGridViewSelectedCellCollection)dataInClipboard; // compiles, but throws exception at runtime

Do I have any other option but parsing each string by a defined formatting?

È stato utile?

Soluzione

You will have to define own format for clipboard, which will do what default one can't do for you.

Simplest solution in this specific case is to convert multi-line breaks into \n and then convert back when you paste, but in any case it means no more

DataGridViewSelectedCellCollection tmpCells = this.MyDataGridView.SelectedCells;
Clipboard.SetDataObject(tmpCells);

but

DataGridViewSelectedCellCollection tmpCells = this.MyDataGridView.SelectedCells;
string result = "";
foreach(DataGridViewCell cell in tempCells)
    // ... try to replicate what default clipboard text representation does
// change line breaks
Clipboard.SetDataObject(result.Replace("\xd\xa", "\\n"));

and paste will be:

IDataObject dataInClipboard = Clipboard.GetDataObject();
string stringInClipboard = dataInClipboard.GetData(DataFormats.Text).ToString().Replace("\\n", "\xd\xa");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top