Como copiar y pegar en Excel desde un DataGridView
Cuando se seleccionan varias filas en un control DataGridView y se pulsa Ctrl+C para copiar su contenido, el comportamiento por defecto copia los valores de las celdas en formato de texto plano separado por tabuladores. Con esto solo ya se pueden pegar los datos en una hoja Excel, pero podemos implementar este comportamiento de una forma más sofisticada de manera que apliquemos un formato personalizado a las columnas en función del tipo de los datos de cada celda.
Los datos de una hoja Excel se pueden importar y exportar en formato XML según un esquema de documento predefinido, pero también es capaz de interpretar tablas HTML y convertirlas en tablas Excel. Esto es lo que vamos a hacer para exportar las celdas seleccionadas desde el DataGridView.
En primer lugar, escribimos una función para transformar las filas seleccionadas en una tabla HTML:
private void CopyToExcel(bool hdr)
{
if (dataGrid.SelectedRows.Count > 0)
{
string scopy = "<table>{0}<tbody>";
string sheaders = "";
foreach (DataGridViewRow row in dataGrid.SelectedRows)
{
if (hdr && string.IsNullOrEmpty(sheaders))
{
sheaders = "<theader><tr>";
foreach (DataGridViewCell cell in row.Cells)
{
sheaders += "<th>" + cell.OwningColumn.HeaderText +
"</th>";
}
sheaders += "</tr></theader>";
}
scopy += "<tr>";
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.Value != null)
{
if (cell.ValueType == typeof(DateTime))
{
scopy +=
"<td style=mso-number-format:\"dd/MM/yyyy HH:mm\">"
+ cell.Value.ToString() + "</td>";
}
else if (cell.ValueType == typeof(bool))
{
scopy += "<td style=mso-number-format:\"\\@\">" +
(Convert.ToBoolean(cell.Value) ? "Yes" : "No") +
"</td>";
}
else if (cell.ValueType == typeof(int))
{
scopy += "<td style=mso-number-format:\"0\">" +
cell.Value.ToString() + "</td>";
}
else if (cell.ValueType == typeof(double))
{
scopy += "<td style=mso-number-format:\"0.00\">" +
cell.Value.ToString() + "</td>";
}
else
{
scopy += "<td style=mso-number-format:\"\\@\">" +
cell.Value.ToString() + "</td>";
}
}
else
{
scopy += "<td style=mso-number-format:\"\\@\"/>";
}
}
scopy += "</tr>";
}
scopy += "</tbody></table>";
Clipboard.SetData(DataFormats.Text, string.Format(scopy, sheaders));
}
}
El parámetro hdr de la función indica si debemos copiar también los encabezados de las columnas, y, para aplicar el formato correcto a cada celda, utilizamos el elemento mso-number-format para definir el estilo de la celda, en este caso, basándonos en el tipo de datos que contiene.
Ahora solo falta llamar a esta función en algún evento de teclado cuando el usuario pulse la combinación de teclas Ctl+C, por ejemplo en KeyDown:
private void dataGrid_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == Keys.C) && (e.Modifiers == Keys.Control))
{
CopyToExcel(true);
e.Handled = true;
}
}
Es importante poner a true la propiedad e.Handled, ya que, de lo contrario, el comportamiento por defecto del control sobrescribirá los datos del portapapeles.