使用所有单元格格式将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中的确切格式?

更新:现在可以在GitHub中找到: https : //github.com/MeaningOfLights/DataGridToHTML


我很难理解为什么这不重复。 整个网络和这里都有例子 。

令我惊讶的是,在经过大量研究后,没有完整的示例将DataGridView导出到HTML或Excel,并在互联网上的任何位置进行格式化 – 直到现在:)

在您的问题中查看此代码,您已经发现使用Interop复制大型数据集的速度有多慢并且选择使用剪贴板:

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

这个问题的关键是 – 使用DataGridView上的剪贴板不包含单元格格式。 因为剪贴板不包含格式化,所以您必须回到原来的慢速性能问题,即必须单独设置单元格样式,使用Interop非常非常慢。

在这种情况下,您的项目可能更适合使用XML而不是Interop创建Excel文件。 虽然我第一次认为这将是一个很好的解决方法,而DartAlex的另一个答案表明,我认为我会编写一个可以使用Clipboard方法的答案。 获取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("
"); sb.AppendLine(""); //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(""); } sb.AppendLine(""); //create table body for (int rowIndex = 0; rowIndex < dgv.Rows.Count; rowIndex++) { sb.AppendLine(""); 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(""); } sb.AppendLine(""); } //table footer & end of html file sb.AppendLine("
"); 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(""); return sb.ToString(); } public string DGVCellToHTMLWithFormatting(DataGridView dgv, int row, int col) { StringBuilder sb = new StringBuilder(); 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(""); if (font.Italic) sb.Append(""); if (font.Strikeout) sb.Append(""); //The element was deprecated in HTML 4.01. The new HTML 5 tag is: text-decoration: underline if (font.Underline) sb.Append(""); string size = string.Empty; if (font.Size != this.Font.Size) size = "font-size: " + font.Size + "pt;"; //The tag is not supported in HTML5. Use CSS or a span instead. if (font.FontFamily.Name != this.Font.Name) { sb.Append(""); } sb.Append(value); if (font.FontFamily.Name != this.Font.Name) sb.Append(""); if (font.Underline) sb.Append(""); if (font.Strikeout) sb.Append(""); if (font.Italic) sb.Append(""); if (font.Bold) sb.Append(""); 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 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,轰!
Coding,Fun,YeeHaa,ABS TableName
您好,world,Population.html,表1。
人口统计学,310102.xls,Comp.html,表2。

您的问题的关键是使用DataGridView上的剪贴板不包含单元格格式。 由于剪贴板不包含格式,因此您必须回到单独设置单元格样式的原始慢速性能问题,使用Interop非常非常慢。

在这种情况下,使用XML而不是Interop创建Excel文件会更好。 下面是一个使用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"); } } 

似乎我找到了使用interop和EPPlus的解决方案。 我使用上面的代码只复制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(); }