使用所有单元格格式将dataGridView导出到Excel

我有这个代码,我知道它的工作很快

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); })); } 

代码工作正常,但它只复制的值是Excel,不复制也单元格式(包装文本,背景颜色,字体,边界等)任何人都可以帮助我在这一个? 如何完成此代码具有像DataGridView中的确切格式?

我很难理解为什么这不是重复的。 有networking和这里的 例子 。

令我惊讶的是经过大量的研究,还没有完整的例子将DataGridView导出到HTML或Excel格式的互联网上的任何地方 – 直到现在:)

在你的问题中查看这段代码,你已经发现使用Interop复制大型数据集的速度有多慢,并select使用剪贴板:

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

这个问题的症结在于 – 在DataGridView上使用剪贴板不包含单元格格式。 由于剪贴板不包含格式,因此您可能会回到原来的缓慢性能问题,即必须单独设置“单元格样式”,而使用Interop的格式非常非常慢。

在这种情况下,您的项目可能会更好地使用XML而不是Interop来创buildExcel文件。 虽然我第一次认为这将是一个很好的解决方法,DartAlex的其他答案表明,我认为我会编写一个答案,您可以使用剪贴板方法。 获取DataGridViewHTML副本并将 其格式化并粘贴到Excel中:

DataGridView格式化HTML表格,然后到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:

魔术,阿布拉,Cadabra,轰!
编码,乐趣,YeeHaa,ABS表名
你好,world,Population.html,表1
人口统计,310102.xls,Comp.html,表2。

我将尝试将这些代码作为一个GitHub项目提供给其他人使用,以扩展和优化它,并保持HTML和Exel版本的最新状态。

您的问题的症结是使用DataGridView上的剪贴板不包含单元格格式。 因为剪贴板不包含格式化,所以您可能会回到原来的缓慢性能问题,即必须单独设置“单元格样式”,而使用Interop的单元格样式非常非常慢。

在这种情况下,使用XML而不是Interop创buildExcel文件会更好。 以下是使用ClosedXML将格式化DataGridView导出到Excel的方法。

 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"); } } 

我似乎find了使用interop和EPPlus的解决scheme。 我只使用上面的代码来复制Excel中的值,然后使用下面的代码(EPPlus代码)从dataGridView中获取格式。 这个代码依赖于你想从dataGridView中获取什么。 在下面的代码中,我想从第一行中取出WrapText,并从每个写入的单元格中获取背景颜色

 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(); }