formato exportar encabezados con c# .net datagridview excel-interop cell-formatting

c# - exportar - Exporte el dataGridView a Excel con todos los formatos de celdas



exportar datagridview a excel c# con encabezados (3)

Actualización: ahora disponible en GitHub: https://github.com/MeaningOfLights/DataGridToHTML

Me cuesta entender por qué esto no es un duplicado. Hay ejemplos en toda la red y here .

Para mi sorpresa y después de mucha investigación, no hay ejemplos completos de Exportar DataGridView a HTML o Excel con formato en cualquier lugar de Internet, hasta ahora :)

Al observar este código en su pregunta, ha descubierto lo lento que es copiar grandes conjuntos de datos con Interop y ha optado por utilizar el Portapapeles en su lugar:

dataGridViewControl.SelectAll(); DataObject dataObj = dataGridViewControl.GetClipboardContent(); if (dataObj != null) Invoke((Action)(() => { Clipboard.SetDataObject(dataObj); }));

El quid de esta pregunta es: usar el Portapapeles en un DataGridView no contiene el Formato de celda. Debido a que el portapapeles no contiene el formato, vuelve al problema original de rendimiento lento de tener que configurar los Estilos de celda individualmente, lo que usando Interop es muy, muy lento.

En este caso, podría funcionar mejor para su proyecto crear archivos de Excel utilizando XML en lugar de Interop . Aunque primero pensé que esta sería una buena solución y la otra respuesta aquí de DartAlex lo demuestra, pensé en codificar una respuesta que puede usar con el método Portapapeles. Obteniendo una copia HTML de DataGridView con formato y pegándolo en Excel:

DataGridView a tabla HTML con formato y luego en Excel

//==================================================== //DataGridView Export To HTML by Jeremy Thompson: https://stackoverflow.com/questions/39210329/ //==================================================== public string ConvertDataGridViewToHTMLWithFormatting(DataGridView dgv) { StringBuilder sb = new StringBuilder(); //create html & table sb.AppendLine("<html><body><center><table border=''1'' cellpadding=''0'' cellspacing=''0''>"); sb.AppendLine("<tr>"); //create table header for (int i = 0; i < dgv.Columns.Count; i++) { sb.Append(DGVHeaderCellToHTMLWithFormatting(dgv, i)); sb.Append(DGVCellFontAndValueToHTML(dgv.Columns[i].HeaderText, dgv.Columns[i].HeaderCell.Style.Font)); sb.AppendLine("</td>"); } sb.AppendLine("</tr>"); //create table body for (int rowIndex = 0; rowIndex < dgv.Rows.Count; rowIndex++) { sb.AppendLine("<tr>"); foreach (DataGridViewCell dgvc in dgv.Rows[rowIndex].Cells) { sb.AppendLine(DGVCellToHTMLWithFormatting(dgv, rowIndex, dgvc.ColumnIndex)); string cellValue = dgvc.Value == null ? string.Empty : dgvc.Value.ToString(); sb.AppendLine(DGVCellFontAndValueToHTML(cellValue, dgvc.Style.Font)); sb.AppendLine("</td>"); } sb.AppendLine("</tr>"); } //table footer & end of html file sb.AppendLine("</table></center></body></html>"); return sb.ToString(); } //TODO: Add more cell styles described here: https://msdn.microsoft.com/en-us/library/1yef90x0(v=vs.110).aspx public string DGVHeaderCellToHTMLWithFormatting(DataGridView dgv, int col) { StringBuilder sb = new StringBuilder(); sb.Append("<td"); sb.Append(DGVCellColorToHTML(dgv.Columns[col].HeaderCell.Style.ForeColor, dgv.Columns[col].HeaderCell.Style.BackColor)); sb.Append(DGVCellAlignmentToHTML(dgv.Columns[col].HeaderCell.Style.Alignment)); sb.Append(">"); return sb.ToString(); } public string DGVCellToHTMLWithFormatting(DataGridView dgv, int row, int col) { StringBuilder sb = new StringBuilder(); sb.Append("<td"); sb.Append(DGVCellColorToHTML(dgv.Rows[row].Cells[col].Style.ForeColor, dgv.Rows[row].Cells[col].Style.BackColor)); sb.Append(DGVCellAlignmentToHTML(dgv.Rows[row].Cells[col].Style.Alignment)); sb.Append(">"); return sb.ToString(); } public string DGVCellColorToHTML(Color foreColor, Color backColor) { if (foreColor.Name == "0" && backColor.Name == "0") return string.Empty; StringBuilder sb = new StringBuilder(); sb.Append(" style=/""); if (foreColor.Name != "0" && backColor.Name != "0") { sb.Append("color:#"); sb.Append(foreColor.R.ToString("X2") + foreColor.G.ToString("X2") + foreColor.B.ToString("X2")); sb.Append("; background-color:#"); sb.Append(backColor.R.ToString("X2") + backColor.G.ToString("X2") + backColor.B.ToString("X2")); } else if (foreColor.Name != "0" && backColor.Name == "0") { sb.Append("color:#"); sb.Append(foreColor.R.ToString("X2") + foreColor.G.ToString("X2") + foreColor.B.ToString("X2")); } else //if (foreColor.Name == "0" && backColor.Name != "0") { sb.Append("background-color:#"); sb.Append(backColor.R.ToString("X2") + backColor.G.ToString("X2") + backColor.B.ToString("X2")); } sb.Append(";/""); return sb.ToString(); } public string DGVCellFontAndValueToHTML(string value,Font font) { //If no font has been set then assume its the default as someone would be expected in HTML or Excel if (font == null || font == this.Font && !(font.Bold | font.Italic | font.Underline | font.Strikeout)) return value; StringBuilder sb = new StringBuilder(); sb.Append(" "); if (font.Bold) sb.Append("<b>"); if (font.Italic) sb.Append("<i>"); if (font.Strikeout) sb.Append("<strike>"); //The <u> element was deprecated in HTML 4.01. The new HTML 5 tag is: text-decoration: underline if (font.Underline) sb.Append("<u>"); string size = string.Empty; if (font.Size != this.Font.Size) size = "font-size: " + font.Size + "pt;"; //The <font> tag is not supported in HTML5. Use CSS or a span instead. if (font.FontFamily.Name != this.Font.Name) { sb.Append("<span style=/"font-family: "); sb.Append(font.FontFamily.Name); sb.Append("; "); sb.Append(size); sb.Append("/">"); } sb.Append(value); if (font.FontFamily.Name != this.Font.Name) sb.Append("</span>"); if (font.Underline) sb.Append("</u>"); if (font.Strikeout) sb.Append("</strike>"); if (font.Italic) sb.Append("</i>"); if (font.Bold) sb.Append("</b>"); return sb.ToString(); } public string DGVCellAlignmentToHTML(DataGridViewContentAlignment align) { if (align == DataGridViewContentAlignment.NotSet) return string.Empty; string horizontalAlignment = string.Empty; string verticalAlignment = string.Empty; CellAlignment(align, ref horizontalAlignment, ref verticalAlignment); StringBuilder sb = new StringBuilder(); sb.Append(" align=''"); sb.Append(horizontalAlignment); sb.Append("'' valign=''"); sb.Append(verticalAlignment); sb.Append("''"); return sb.ToString(); } private void CellAlignment(DataGridViewContentAlignment align, ref string horizontalAlignment, ref string verticalAlignment) { switch (align) { case DataGridViewContentAlignment.MiddleRight: horizontalAlignment = "right"; verticalAlignment = "middle"; break; case DataGridViewContentAlignment.MiddleLeft: horizontalAlignment = "left"; verticalAlignment = "middle"; break; case DataGridViewContentAlignment.MiddleCenter: horizontalAlignment = "centre"; verticalAlignment = "middle"; break; case DataGridViewContentAlignment.TopCenter: horizontalAlignment = "centre"; verticalAlignment = "top"; break; case DataGridViewContentAlignment.BottomCenter: horizontalAlignment = "centre"; verticalAlignment = "bottom"; break; case DataGridViewContentAlignment.TopLeft: horizontalAlignment = "left"; verticalAlignment = "top"; break; case DataGridViewContentAlignment.BottomLeft: horizontalAlignment = "left"; verticalAlignment = "bottom"; break; case DataGridViewContentAlignment.TopRight: horizontalAlignment = "right"; verticalAlignment = "top"; break; case DataGridViewContentAlignment.BottomRight: horizontalAlignment = "right"; verticalAlignment = "bottom"; break; default: //DataGridViewContentAlignment.NotSet horizontalAlignment = "left"; verticalAlignment = "middle"; break; } } //Easy repro - copy/paste all this code in a Winform app! public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { string configFile = System.IO.Path.Combine(Application.StartupPath.Replace("//bin//Debug", ""), "testData.csv"); List<string[]> rows = System.IO.File.ReadAllLines(configFile).Select(x => x.Split('','')).ToList(); DataTable dataTable = new DataTable(); dataTable.Columns.Add("testing"); dataTable.Columns.Add("one"); dataTable.Columns.Add("two"); dataTable.Columns.Add("three"); rows.ForEach(x => { dataTable.Rows.Add(x); }); this.dgv.DataSource = dataTable; dgv.Columns[0].HeaderCell.Style.Font = new Font(this.Font, FontStyle.Strikeout); dgv[0, 0].Style.BackColor = Color.Aqua; dgv[1, 0].Style.Alignment = DataGridViewContentAlignment.BottomRight; dgv[2, 0].Style.Font = new Font(new FontFamily("Calibri"),(float)16); dgv[3, 0].Style.ForeColor = Color.Red; dgv[0, 1].Style.Font = new Font(this.Font, FontStyle.Bold); dgv[1, 1].Style.Font = new Font(this.Font, FontStyle.Underline); dgv[2, 1].Style.Font = new Font(this.Font, FontStyle.Italic); dgv[3, 1].Style.Font = new Font(this.Font, FontStyle.Bold | FontStyle.Underline); dgv[3, 1].Style.ForeColor = Color.Green; dgv[3, 1].Style.BackColor = Color.Yellow; dgv[0, 2].Style.Font = new Font(new FontFamily("Times New Roman"), (float)18); dgv[1, 2].Style.Font = new Font(new FontFamily("Georgia"), (float)12); dgv[2, 2].Style.Font = new Font(new FontFamily("Arial"), (float)14); dgv[3, 2].Style.Font = new Font(new FontFamily("Verdana"), (float)18); dgv[0, 3].Style.Font = new Font(new FontFamily("Courier New"), (float)11); dgv[1, 3].Style.Font = new Font(new FontFamily("Lucida Console"), (float)18); dgv[2, 3].Style.Font = new Font(new FontFamily("Times"), (float)14); dgv[3, 3].Style.Font = new Font(new FontFamily("serif"), (float)12); } private void button1_Click(object sender, EventArgs e) { string dgvToHTMLTable = ConvertDataGridViewToHTMLWithFormatting(dgv); Clipboard.SetText(dgvToHTMLTable); }

TestData.csv:

Magia, Abra, Cadabra, Boom!
Codificación, Diversión, YeeHaa, ABS TableName
Hola, mundo, Population.html, TABLA 1.
Demografía, 310102.xls, Comp.html, TABLA 2.

Tengo este código que sé que funciona rápido

CopyAlltoClipboard(dataGridViewControl); Microsoft.Office.Interop.Excel.Application xlexcel; Microsoft.Office.Interop.Excel.Workbook xlWorkBook; Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet; object misValue = System.Reflection.Missing.Value; xlexcel = new Excel.Application(); xlexcel.Visible = true; xlWorkBook = xlexcel.Workbooks.Add(misValue); xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); xlWorkSheet.Name = page.Name; Excel.Range CR = (Excel.Range)xlWorkSheet.Cells[1, 1]; CR.Select(); xlWorkSheet.PasteSpecial(CR, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true); ((Microsoft.Office.Interop.Excel.Range)xlWorkSheet.Range["A1"]).EntireColumn.Delete(null); // delete the first column that has rows indexes xlWorkBook.SaveAs(fileName); private void CopyAlltoClipboard(DataGridView dataGridViewControl) { dataGridViewControl.SelectAll(); DataObject dataObj = dataGridViewControl.GetClipboardContent(); if (dataObj != null) Invoke((Action)(() => { Clipboard.SetDataObject(dataObj); })); }

El código funciona bien, pero solo copia los valores, es el Excel, no copia también el formato de las celdas (texto de ajuste, color de fondo, fuente, bordes, etc.) ¿Alguien puede ayudarme en este? ¿Cómo completar este código que tiene el formato exacto como en DataGridView?


El quid de su pregunta es usar el Portapapeles en un DataGridView que no contiene Formato de celda. Debido a que el Portapapeles no contiene el formato, regresó al problema original de rendimiento lento de tener que configurar los Estilos de celda individualmente, lo que usando Interop es muy, muy lento.

En este caso, funcionará mejor crear archivos de Excel utilizando XML en lugar de Interop. A continuación se muestra un método que usa ClosedXML para exportar un DataGridView a Excel con formato.

using ClosedXML.Excel; public void ExportToExcelWithFormatting(DataGridView dataGridView1) { string fileName; SaveFileDialog saveFileDialog1 = new SaveFileDialog(); saveFileDialog1.Filter = "xls files (*.xlsx)|*.xlsx|All files (*.*)|*.*"; saveFileDialog1.Title = "To Excel"; saveFileDialog1.FileName = this.Text + " (" + DateTime.Now.ToString("yyyy-MM-dd") + ")"; if (saveFileDialog1.ShowDialog() == DialogResult.OK) { fileName = saveFileDialog1.FileName; var workbook = new XLWorkbook(); var worksheet = workbook.Worksheets.Add(this.Text); for (int i = 0; i < dataGridView1.Columns.Count; i++) { worksheet.Cell(1, i + 1).Value = dataGridView1.Columns[i].Name; } for (int i = 0; i < dataGridView1.Rows.Count; i++) { for (int j = 0; j < dataGridView1.Columns.Count; j++) { worksheet.Cell(i + 2, j + 1).Value = dataGridView1.Rows[i].Cells[j].Value.ToString(); if (worksheet.Cell(i + 2, j + 1).Value.ToString().Length > 0) { XLAlignmentHorizontalValues align; switch (dataGridView1.Rows[i].Cells[j].Style.Alignment) { case DataGridViewContentAlignment.BottomRight: align = XLAlignmentHorizontalValues.Right; break; case DataGridViewContentAlignment.MiddleRight: align = XLAlignmentHorizontalValues.Right; break; case DataGridViewContentAlignment.TopRight: align = XLAlignmentHorizontalValues.Right; break; case DataGridViewContentAlignment.BottomCenter: align = XLAlignmentHorizontalValues.Center; break; case DataGridViewContentAlignment.MiddleCenter: align = XLAlignmentHorizontalValues.Center; break; case DataGridViewContentAlignment.TopCenter: align = XLAlignmentHorizontalValues.Center; break; default: align = XLAlignmentHorizontalValues.Left; break; } worksheet.Cell(i + 2, j + 1).Style.Alignment.Horizontal = align; XLColor xlColor = XLColor.FromColor(dataGridView1.Rows[i].Cells[j].Style.SelectionBackColor); worksheet.Cell(i + 2, j + 1).AddConditionalFormat().WhenLessThan(1).Fill.SetBackgroundColor(xlColor); worksheet.Cell(i + 2, j + 1).Style.Font.FontName = dataGridView1.Font.Name; worksheet.Cell(i + 2, j + 1).Style.Font.FontSize = dataGridView1.Font.Size; } } } worksheet.Columns().AdjustToContents(); workbook.SaveAs(fileName); //MessageBox.Show("Done"); } }


Parece que encontré una solución usando interop y EPPlus. Usé el código anterior solo para copiar los valores en Excel y luego uso este código a continuación (código EPPlus) para tomar el formato de dataGridView. Este código depende de lo que quiera tomar de dataGridView. En este código a continuación, quería tomar el WrapText de la primera fila y los colores de fondo de cada celda escrita

private void FinalizeWorkbook(DataTableReportParam reportParam, DataGridView dataGridViewControl) { FileInfo newFile = new FileInfo(reportParam.FileName); ExcelPackage pck = new ExcelPackage(newFile); IWorksheet worksheet = pck.Workbook.Worksheets[1]; // wrap text and color the crashes with problems (header) for (int col = 1; col <= worksheet.Dimension.End.Column; col++) { worksheet[1, col].WrapText = true; worksheet[1, col].AutofitRows(); if (String.Compare(dataGridViewControl[col - 1, 0].Style.BackColor.Name, "0") != 0) worksheet[1, col].CellStyle.Color = dataGridViewControl[col - 1, 0].Style.BackColor; } // color the cells for (int row = 2; row <= worksheet.Dimension.End.Row; row++) { for (int col = 1; col <= worksheet.Dimension.End.Column; col++) { if (String.Compare(dataGridViewControl[col - 1, row - 1].Style.BackColor.Name, "0") != 0) worksheet[row, col].CellStyle.Color = dataGridViewControl[col - 1, row - 1].Style.BackColor; } } //save and dispose pck.Save(); pck.Dispose(); }