简体   繁体   English

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

[英]Export the dataGridView to Excel with all the cells format

I have this code that I know that it works fast我有这段代码,我知道它运行得很快

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

The code works fine, but it does copy only the values is the excel, doesn't copy also the cells format (wrap text, backcolor, font, borders etc) Can anyone help me on this one?代码工作正常,但它只复制值是 excel,不复制单元格格式(换行文本、背景色、字体、边框等)有人可以帮我解决这个问题吗? How to complete this code the have the exact format like in DataGridView?如何完成此代码具有与 DataGridView 中相同的格式?

Update: Now available in GitHub: https://github.com/MeaningOfLights/DataGridToHTML更新:现在在 GitHub 中可用: https ://github.com/MeaningOfLights/DataGridToHTML


I'm struggling to understand why this isn't a duplicate.我很难理解为什么这不是重复的。 There are examples all over the net and here .网上和这里都有例子

To my surprise & after a lot of research there are no thorough examples of Exporting DataGridView to HTML or Excel with formatting anywhere on the internet - until now :)令我惊讶的是,经过大量研究,在互联网上的任何地方都没有将 DataGridView 导出为 HTML 或 Excel 并格式化的完整示例 -直到现在:)

Looking at this code in your question you have found out how slow it is to copy large datasets with Interop and have opted to use the Clipboard instead:查看问题中的这段代码,您会发现使用 Interop 复制大型数据集有多慢,并选择使用剪贴板:

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

The crux of this question is - using the Clipboard on a DataGridView does not contain the Cell Formatting.这个问题的症结在于 - 在 DataGridView 上使用剪贴板不包含单元格格式。 Because the clipboard doesn't contain the formatting you're back to the original slow performance problem of having to set Cell Styles individually, which using Interop is very, very slow.因为剪贴板不包含格式,您又回到了原来的性能缓慢问题,即必须单独设置单元格样式,使用互操作非常非常慢。

In this case it might work better to create Excel files using XML instead of Interop .在这种情况下,使用XML 而不是 Interop创建 Excel 文件可能会更好。 So while I first thought this would be a good workaround and the other answer here by DartAlex demonstrates that, I thought I'd code up an answer you can use with the Clipboard method.因此,虽然我最初认为这将是一个很好的解决方法,并且 DartAlex 的另一个答案证明了这一点,但我想我会编写一个可以与剪贴板方法一起使用的答案。 Getting a HTML Copy of the DataGridView with formatting and pasting that into Excel:获取带有格式的 DataGridView 的 HTML 副本并将其粘贴到 Excel 中:

DataGridView To HTML Table with Formatting and then into 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:测试数据.csv:

Magic,Abra,Cadabra,Boom!魔术,阿布拉,卡达布拉,轰隆隆!
Coding,Fun,YeeHaa,ABS TableName Coding,Fun,YeeHaa,ABS 表名
Hello,world,Population.html,TABLE 1.你好,世界,Population.html,表 1。
Demography,310102.xls,Comp.html,TABLE 2.人口统计,310102.xls,Comp.html,表 2。

The crux of your question is using the Clipboard on a DataGridView does not contain Cell Formatting.您问题的症结是在 DataGridView 上使用剪贴板不包含单元格格式。 Because the Clipboard doesn't contain the formatting you're back to the original slow performance problem of having to set Cell Styles individually, which using Interop is very, very slow.因为剪贴板不包含格式,您又回到了原来的性能缓慢问题,即必须单独设置单元格样式,使用互操作非常非常慢。

In this case it will work better to create Excel files using XML instead of Interop.在这种情况下,使用 XML 而不是 Interop 创建 Excel 文件会更好。 Below is a method using ClosedXML to export a DataGridView to Excel with formatting.下面是使用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");
    }
}

It seems that I found a solution using interop and EPPlus.看来我找到了使用互操作和 EPPlus 的解决方案。 I used the code above only to copy the values in Excel and then use this code below (EPPlus code) to take the format from dataGridView.我使用上面的代码仅复制 Excel 中的值,然后使用下面的代码(EPPlus 代码)从 dataGridView 中获取格式。 This code depends or what you want to take from the dataGridView.此代码取决于或您想从 dataGridView 中获取什么。 In this code below I wanted to take the WrapText from the first row and the background colors from each written cell在下面的这段代码中,我想从第一行获取 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM