如何在按钮点击时立即将dataGridView数据导出到Excel?

时间:2013-08-12 07:59:46

标签: c# datagridview copy export-to-excel export-to-csv

我的数据网格视图中有10k行和15列。我想将此数据导出到excel表单o按钮。我已经尝试过以下代码。

private void btExport_Click(object sender, EventArgs e)
    {
        Microsoft.Office.Interop.Excel._Application app  = new Microsoft.Office.Interop.Excel.Application();
        Microsoft.Office.Interop.Excel._Workbook workbook =  app.Workbooks.Add(Type.Missing);        
        Microsoft.Office.Interop.Excel._Worksheet worksheet = null;                   
        app.Visible = true;
        worksheet = workbook.Sheets["Sheet1"];
        worksheet = workbook.ActiveSheet;                  
        for(int i=1;i<dataGridView1.Columns.Count+1;i++)
        {
             worksheet.Cells[1, i] = dataGridView1.Columns[i-1].HeaderText;
        }    
        for (int i=0; i < dataGridView1.Rows.Count-1 ; i++)
        {
            for(int j=0;j<dataGridView1.Columns.Count;j++)
            {
                if (dataGridView1.Rows[i].Cells[j].Value != null)
                {
                    worksheet.Cells[i + 2, j + 1] = dataGridView1.Rows[i].Cells[j].Value.ToString();
                }
                else
                {
                    worksheet.Cells[i + 2, j + 1] = "";
                }
            }
        }
    }

这对我有用,但需要花费大量时间来完成导出过程。

是否可以通过dataGridView(包含10k行)从按钮点击中立即退出?

除此之外,当我尝试将所有dataGridview内容复制到剪贴板然后手动将其粘贴到Excel工作表时,它几乎立即发生。

那么有没有办法将所有dataGridView单元格复制到剪贴板并在点击按钮时将其粘贴到excel表格(带单元格格式)?

我有如下复制到剪贴板的代码,但我不知道如何通过打开它将其粘贴到新的Excel工作表中。

        private void copyAllToolStripMenuItem_Click(object sender, EventArgs e)
    {
        dataGridView1.SelectAll();
        DataObject dataObj = dataGridView1.GetClipboardContent();
        if (dataObj != null)
            Clipboard.SetDataObject(dataObj);
    }

请帮助举个例子。我是C#的新手。

14 个答案:

答案 0 :(得分:60)

我通过简单的复制和粘贴方法解决了这个问题。我不知道这是最好的方法,但对我而言,它的效果很好,而且几乎是即时的。这是我的代码。

    private void copyAlltoClipboard()
    {
        dataGridView1.SelectAll();
        DataObject dataObj = dataGridView1.GetClipboardContent();
        if (dataObj != null)
            Clipboard.SetDataObject(dataObj);
    }
    private void button3_Click_1(object sender, EventArgs e)
    {
        copyAlltoClipboard();
        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);
        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);          
    }

感谢。

答案 1 :(得分:25)

这是一个很好的问题,我很惊讶找到一个清晰而完整的答案是多么困难,我发现的大部分答案都是sudo-code或者不是100%完成。

我能够创建一个完整的解决方案,根据Jake的答案将数据从我的DataGridView复制并保存到excel文件中,所以我发布了我的完整解决方案,希望它可以帮助其他新来者像我一样:)

首先,您需要项目中的Microsoft.Office.Interop.Excel引用。请参阅MSDN了解如何添加它。

我的代码:

using Excel = Microsoft.Office.Interop.Excel;

private void btnExportToExcel_Click(object sender, EventArgs e)
{
    SaveFileDialog sfd = new SaveFileDialog();
    sfd.Filter = "Excel Documents (*.xls)|*.xls";
    sfd.FileName = "Inventory_Adjustment_Export.xls";
    if (sfd.ShowDialog() == DialogResult.OK)
    {
        // Copy DataGridView results to clipboard
        copyAlltoClipboard();

        object misValue = System.Reflection.Missing.Value;
        Excel.Application xlexcel = new Excel.Application();

        xlexcel.DisplayAlerts = false; // Without this you will get two confirm overwrite prompts
        Excel.Workbook xlWorkBook = xlexcel.Workbooks.Add(misValue);
        Excel.Worksheet xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

        // Format column D as text before pasting results, this was required for my data
        Excel.Range rng = xlWorkSheet.get_Range("D:D").Cells;
        rng.NumberFormat = "@";

        // Paste clipboard results to worksheet range
        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);

        // For some reason column A is always blank in the worksheet. ¯\_(ツ)_/¯
        // Delete blank column A and select cell A1
        Excel.Range delRng = xlWorkSheet.get_Range("A:A").Cells;
        delRng.Delete(Type.Missing);
        xlWorkSheet.get_Range("A1").Select();

        // Save the excel file under the captured location from the SaveFileDialog
        xlWorkBook.SaveAs(sfd.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
        xlexcel.DisplayAlerts = true;
        xlWorkBook.Close(true, misValue, misValue);
        xlexcel.Quit();

        releaseObject(xlWorkSheet);
        releaseObject(xlWorkBook);
        releaseObject(xlexcel);

        // Clear Clipboard and DataGridView selection
        Clipboard.Clear();
        dgvItems.ClearSelection();

        // Open the newly saved excel file
        if (File.Exists(sfd.FileName))
            System.Diagnostics.Process.Start(sfd.FileName);
    }
}

private void copyAlltoClipboard()
{
    dgvItems.SelectAll();
    DataObject dataObj = dgvItems.GetClipboardContent();
    if (dataObj != null)
        Clipboard.SetDataObject(dataObj);
}

private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Exception Occurred while releasing object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

答案 2 :(得分:8)

我不想偷@Jake和@ Cornelius的回答,所以我尝试编辑它。但它被拒绝了。 无论如何,我必须指出的唯一改进是关于在粘贴后避免excel中的额外空白列。添加一行dataGridView1.RowHeadersVisible = false;会隐藏所谓的&#34;行标题&#34;它显示在DataGridView的最左侧部分,因此当您执行dataGridView1.SelectAll();

时,它不会被选中并复制到剪贴板
private void copyAlltoClipboard()
    {
        //to remove the first blank column from datagridview
        dataGridView1.RowHeadersVisible = false;
        dataGridView1.SelectAll();
        DataObject dataObj = dataGridView1.GetClipboardContent();
        if (dataObj != null)
            Clipboard.SetDataObject(dataObj);
    }
    private void button3_Click_1(object sender, EventArgs e)
    {
        copyAlltoClipboard();
        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);
        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);          
    }

答案 3 :(得分:7)

using Excel = Microsoft.Office.Interop.Excel;


private void btnExportExcel_Click(object sender, EventArgs e)
{
    try
    {
        Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
        excel.Visible = true;
        Microsoft.Office.Interop.Excel.Workbook workbook = excel.Workbooks.Add(System.Reflection.Missing.Value);
        Microsoft.Office.Interop.Excel.Worksheet sheet1 = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[1];
        int StartCol = 1;
        int StartRow = 1;
        int j = 0, i = 0;

        //Write Headers
        for (j = 0; j < dgvSource.Columns.Count; j++)
        {
            Microsoft.Office.Interop.Excel.Range myRange = (Microsoft.Office.Interop.Excel.Range)sheet1.Cells[StartRow, StartCol + j];
            myRange.Value2 = dgvSource.Columns[j].HeaderText;
        }

        StartRow++;

        //Write datagridview content
        for (i = 0; i < dgvSource.Rows.Count; i++)
        {
            for (j = 0; j < dgvSource.Columns.Count; j++)
            {
                try
                {
                    Microsoft.Office.Interop.Excel.Range myRange = (Microsoft.Office.Interop.Excel.Range)sheet1.Cells[StartRow + i, StartCol + j];
                    myRange.Value2 = dgvSource[j, i].Value == null ? "" : dgvSource[j, i].Value;
                }
                catch
                {
                    ;
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

答案 4 :(得分:3)

Interop很慢并且有其他问题,使用剪贴板似乎是不可扩展的。 以下是另外两种方法

  1. 直接使用Excel 2007+文件而不是使用Excel,它会更快(更快)。您可以使用Microsoft的SDK OpenXML(http://openxmldeveloper.org/)。学习OpenXML的最佳方法是下载Productivity工具(http://www.microsoft.com/en-us/download/details.aspx?id=5124),它会创建一个现有文件并生成创建它所需的代码。另一个可能更简单的选择是使用ClosedXML(http://closedxml.codeplex.com/)。它似乎更容易使用(查看示例http://closedxml.codeplex.com/wikipage?title=Showcase&referringTitle=Home),但我没有使用它的经验。我确信还有其他库用Excel包装。

  2. 通过OLEDB使用excel。这允许您使用Excel,就好像它是一个dababase。有关示例和详细信息,请参阅http://www.codeproject.com/Articles/8500/Reading-and-Writing-Excel-using-OLEDBPerformance of OLEDB to read Excel

  3. 我从ClosedXML开始。

答案 5 :(得分:3)

Best是使用closedxml.codeplex.com Library.Refer it @ https://closedxml.codeplex.com/wikipage?title=Adding%20DataTable%20as%20Worksheet&referringTitle=Documentation

var wb = new ClosedXML.Excel.XLWorkbook();
DataTable dt = GetTheDataTable();//Refer documentation


wb.Worksheets.Add(dt);

Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=\"FileName.xlsx\"");

using (var ms = new System.IO.MemoryStream()) {
    wb.SaveAs(ms);
    ms.WriteTo(Response.OutputStream);
    ms.Close();
}

Response.End();

答案 6 :(得分:2)

我喜欢杰克的解决方案。执行以下操作可解决无标题的问题

xlWorkSheet.Cells[1, 1] = "Header 1";
xlWorkSheet.Cells[1, 2] = "Header 2";
xlWorkSheet.Cells[1, 3] = "Header 3";

当然这只会让你知道标题应该是提前的。

答案 7 :(得分:1)

这就是我用于gridview的内容,尝试将其用于数据,它完美运行:

        GridView1.AllowPaging = false;
        GridView1.DataBind();

        StringBuilder sb = new StringBuilder();

        for (int k = 0; k < GridView1.Columns.Count; k++)
        {
            //add separator
            sb.Append(GridView1.Columns[k].HeaderText+";");

        }


        //append new line
        sb.Append("\r\n");
        for (int i = 0; i < GridView1.Rows.Count; i++)
        {
            for (int k = 0; k < GridView1.Columns.Count; k++)
            {
                sb.Append(GridView1.Rows[i].Cells[k].Text+";");
            }
            sb.AppendLine();
        }

答案 8 :(得分:1)

这个答案是针对第一个问题,为什么需要花费很多时间,它提供了另一种将DataGridView导出到Excel的解决方案。

MS Office Interop很慢,甚至Microsoft也不建议在服务器端使用Interop,也不能用于导出大型Excel文件。有关详细信息,请参阅Microsoft的why not to use OLE Automation

Interop以XLS文件格式(旧的Excel 97-2003文件格式)保存Excel文件,并且对Office 2003的支持已结束。 Microsoft Excel使用Office 2007发布了XLSX文件格式,并建议使用OpenXML SDK而不是Interop。但是XLSX文件实际上并不是那么快,并且不能很好地处理大型Excel文件,因为它们基于XML文件格式。这就是为什么Microsoft还发布了Office 2007的XLSB文件格式,这是推荐用于大型Excel文件的文件格式。它是二进制格式。因此,最好和最快的解决方案是保存XLSB文件。

您可以使用此C# Excel library来保存XLSB文件,但它也支持XLS和XLSX文件格式。

请参阅以下代码示例,作为将DataGridView导出到Excel的替代方法:

// Create a DataSet and add the DataTable of DataGridView 
DataSet dataSet = new DataSet();
dataSet.Tables.Add((DataTable)dataGridView);
//or ((DataTable)dataGridView.DataSource).Copy() to create a copy

// Export Excel file 
ExcelDocument workbook = new ExcelDocument();
workbook.easy_WriteXLSBFile_FromDataSet(filePath, dataSet, 
     new EasyXLS.ExcelAutoFormat(EasyXLS.Constants.Styles.AUTOFORMAT_EASYXLS1), 
     "Sheet1");

如果您还需要导出DataGridView的格式,请查看此代码示例,了解如何export datagridview to Excel in C#

答案 9 :(得分:0)

此行仅适用于Windows窗体上的DataGridView控件:

...
  volumes:
    - .:/var/www
    - node_modules:/var/www/node_modules

此问题解决了相同的问题,但针对WPF框架的DataGrid控件:

DataObject dataObj = dataGridView1.GetClipboardContent();

答案 10 :(得分:0)

如果您的DataGridView的RightToLeft设置为Yes,那么您的数据将反向复制。因此,您应该使用以下代码正确复制数据。

private void copyAlltoClipboard()
{
    dgvItems.RightToLeft = RightToLeft.No;
    dgvItems.SelectAll();
    DataObject dataObj = dgvItems.GetClipboardContent();
    if (dataObj != null)
        Clipboard.SetDataObject(dataObj);
    dgvItems.RightToLeft = RightToLeft.Yes;
}

答案 11 :(得分:0)

或者,您可以在不使用Office dll的情况下执行快速导出,因为Excel可以解析csv文件而不会出现问题。

执行以下操作(对于少于65.536行的标题):

user.ts code

var submitData =
{
  first_name: formData.firstName,
  last_name: formData.lastName,
  email: formData.email,
  password: formData.password,
  address_1: formData.address1,
  address_2: formData.address2,}

his.appService.createUser(submitData).subscribe((result: any) => {
  if (result != '') {

答案 12 :(得分:0)

我认为这是导出datagridview的最简单且即时的方法。

 try
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Excel Documents (*.xlsx)|*.xlsx";
            sfd.FileName = "ProfitLoss.xlsx";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                DataTable dts = new DataTable();
                for (int i = 0; i < grdProfitAndLoss.Columns.Count; i++)
                {
                    dts.Columns.Add(grdProfitAndLoss.Columns[i].Name);
                }
                for (int j = 0; j < grdProfitAndLoss.Rows.Count; j++)
                {
                    DataRow toInsert = dts.NewRow();
                    int k = 0;
                    int inc = 0;
                    for (k = 0; k < grdProfitAndLoss.Columns.Count; k++)
                    {
                        if (grdProfitAndLoss.Columns[k].Visible == false) { continue; }
                        toInsert[inc] = grdProfitAndLoss.Rows[j].Cells[k].Value;
                        inc++;
                    }
                    dts.Rows.Add(toInsert);
                }
                dts.AcceptChanges();
                ExcelUtlity obj = new ExcelUtlity();
                obj.WriteDataTableToExcel(dts, "Profit And Loss", sfd.FileName, "Profit And Loss");
                MessageBox.Show("Exported Successfully");
            }
        }
        catch (Exception ex)
        {

        }

答案 13 :(得分:0)

我添加这个答案是因为,尽管其他方法都比OpenXML DOM更快,并且比COM / Interop更快,更可靠,但其他方法都没有使用OpenXMLWriter,并且因为其他一些方法都使用了剪贴板,我要提醒您注意,因为它的输出不可靠。

详细信息可以在下面的链接中的答案中找到,但是该示例适用于DataTable,但是您可以通过更改行/列循环以引用dgv而不是dt来使其适合使用DataGridView。

How to export DataTable to Excel