Подтвердить что ты не робот

Как экспортировать данные DataGridView мгновенно в Excel при нажатии кнопки?

У меня есть 10k строк и 15 столбцов в моем представлении сетки данных. Я хочу экспортировать эти данные в файл Excel. Я уже пробовал с приведенным ниже кодом.

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 в клип-панель, а затем вставить его вручную, это произойдет почти мгновенно.

Итак, есть ли способ скопировать все ячейки dataGridView в клип-панель и вставить ее на листы Excel (с форматированием ячейки) на кнопку "<" >

У меня есть код для копирования в буфер обмена, как показано ниже, но я не знаю, как вставить его в новый лист excel, открыв его.

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

Пожалуйста, помогите с примером. Я новичок в С#.

4b9b3361

Ответ 1

Я решил это простым методом копирования и вставки. Я не знаю, что это лучший способ сделать это, но для меня это работает хорошо и почти мгновенно. Вот мой код.

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

Спасибо.

Ответ 2

Это отличный вопрос, и я был удивлен тем, как трудно было найти ясный и полный ответ, большинство ответов, которые я нашел, были либо судо-кодом, либо не заполнены на 100%.

Мне удалось создать полное решение для копирования и сохранения данных из моего 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();
    }
}

Ответ 3

Я не собирался украсть @Jake и @Cornelius ответ, поэтому я попробовал его редактировать. но он был отклонен. В любом случае, единственное улучшение, которое я должен отметить, - это избегать лишнего столбца в excel после вставки. Добавление одной строки dataGridView1.RowHeadersVisible = false; скрывает так называемый "заголовок строки", который появляется в левой части большей части 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);          
    }

Ответ 4

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

Ответ 5

Interop медленный и имеет другие проблемы, использование буфера обмена кажется не расширяемым. Вот еще два способа сделать это

Я бы начал с ClosedXML.

Ответ 6

Лучшим является использование библиотеки 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();

Ответ 7

Мне нравится решение Джейка. Проблема без заголовка разрешается, выполняя следующие

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

Конечно, это только работает, вы знаете, что заголовки должны быть впереди времени.

Ответ 8

что я использую для своего gridview, попробуйте использовать его для данных yr, он отлично работает:

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

Ответ 9

Этот ответ для первого вопроса, почему он занимает так много времени, и предлагает альтернативное решение для экспорта DataGridView в Excel.

MS Office Interop работает медленно, и даже Microsoft не рекомендует использовать Interop на стороне сервера и не может использоваться для экспорта больших файлов Excel. Подробнее см. почему бы не использовать OLE Automation с точки зрения Microsoft.

Interop сохраняет файлы Excel в формате XLS (старый формат файла Excel 97-2003), и поддержка Office 2003 завершена. Microsoft Excel выпустил формат файла XLSX в Office 2007 и рекомендует использовать OpenXML SDK вместо Interop. Но файлы XLSX на самом деле не такие быстрые и не обрабатывают очень большие файлы Excel, потому что они основаны на формате XML файла. Вот почему Microsoft также выпустила XLSB-формат файла с Office 2007, формат файла, который рекомендуется для больших файлов Excel. Это двоичный формат. Поэтому лучшим и быстрым решением является сохранение файлов XLSB.

Вы можете использовать эту библиотеку С# Excel для сохранения файлов 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, проверьте этот пример кода, как экспортировать datagridview в Excel на С#.

Ответ 10

Эта строка работает только для элемента управления DataGridView в Windows Forms:

DataObject dataObj = dataGridView1.GetClipboardContent();

Этот адрес решает ту же проблему, но для элемента управления DataGrid для WPF Framework:

    private void copyDataGridContentToClipboard()
    {
        datagridGrupeProductie.SelectAll();
        datagridGrupeProductie.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;

        ApplicationCommands.Copy.Execute(null, datagridGrupeProductie);
        datagridGrupeProductie.UnselectAll();
    }


    private void rightClickGrupeProductie_Click(object sender, RoutedEventArgs e)
    {
        copyDataGridContentToClipboard();
        Microsoft.Office.Interop.Excel.Application excelApp;
        Microsoft.Office.Interop.Excel.Workbook excelWkbk;
        Microsoft.Office.Interop.Excel.Worksheet excelWksht;
        object misValue = System.Reflection.Missing.Value;
        excelApp = new Microsoft.Office.Interop.Excel.Application();
        excelApp.Visible = true;
        excelWkbk = excelApp.Workbooks.Add(misValue);
        excelWksht = (Microsoft.Office.Interop.Excel.Worksheet)excelWkbk.Worksheets.get_Item(1);
        Microsoft.Office.Interop.Excel.Range CR = (Microsoft.Office.Interop.Excel.Range)excelWksht.Cells[1, 1];
        CR.Select();
        excelWksht.PasteSpecial(CR, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true);
    }

Ответ 11

Если ваш 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;
}

Ответ 12

В качестве альтернативы вы можете выполнить быстрый экспорт без использования Office DLL, так как Excel может без проблем анализировать CSV файлы.

Делаем что-то вроде этого (для менее чем 65,536 строк с заголовками):

  Try

            If (p_oGrid.RowCount = 0) Then
                MsgBox("No data", MsgBoxStyle.Information, "App")
                Exit Sub
            End If

            Cursor.Current = Cursors.WaitCursor

            Dim sText As New System.Text.StringBuilder
            Dim sTmp As String
            Dim aVisibleData As New List(Of String)

            For iAuxRow As Integer = 0 To p_oGrid.Columns.Count - 1
                If p_oGrid.Columns(iAuxRow).Visible Then
                    aVisibleData.Add(p_oGrid.Columns(iAuxRow).Name)
                    sText.Append(p_oGrid.Columns(iAuxRow).HeaderText.ToUpper)
                    sText.Append(";")
                End If
            Next
            sText.AppendLine()

            For iAuxRow As Integer = 0 To p_oGrid.RowCount - 1
                Dim oRow As DataGridViewRow = p_oGrid.Rows(iAuxRow)
                For Each sCol As String In aVisibleData
                    Dim sVal As String
                    sVal = oRow.Cells(sCol).Value.ToString()
                    sText.Append(sVal.Replace(";", ",").Replace(vbCrLf, " ; "))
                    sText.Append(";")
                Next
                sText.AppendLine()
            Next

            sTmp = IO.Path.GetTempFileName & ".csv"
            IO.File.WriteAllText(sTmp, sText.ToString, System.Text.Encoding.UTF8)
            sText = Nothing

            Process.Start(sTmp)

        Catch ex As Exception
            process_error(ex)
        Finally
            Cursor.Current = Cursors.Default
        End Try