web-dev-qa-db-fra.com

Comment exporter des données dataGridView instantanément vers Excel en cliquant sur un bouton?

J'ai 10k lignes et 15 colonnes dans ma vue de grille de données. Je souhaite exporter ces données vers une feuille Excel avec un clic de bouton. J'ai déjà essayé avec le code ci-dessous.

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] = "";
                }
            }
        }
    }

Cela fonctionne pour moi mais cela prend beaucoup de temps pour terminer le processus d'exportation.

Est-il possible d'exporter de dataGridView (avec 10k lignes) vers Excel instantanément sur un clic de bouton?

En dehors de cela, lorsque j'ai essayé de copier tout le contenu de dataGridview dans le presse-papiers, puis de le coller manuellement dans une feuille Excel, cela se produit presque instantanément. 

Alors, y a-t-il un moyen de copier toutes les cellules de dataGridView dans le presse-papiers et de les coller dans une feuille Excel (avec le formatage de cellules) en un clic?

J'ai le code pour copier dans le presse-papiers comme ci-dessous, mais je ne sais pas comment le coller dans une nouvelle feuille Excel en l'ouvrant.

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

S'il vous plaît aider avec un exemple. Je suis nouveau en C #.

32
Jake

J'ai résolu ceci par simple copier/coller. Je ne sais pas si c'est la meilleure façon de faire mais, pour moi, cela fonctionne bien et presque instantanément. Voici mon code.

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

Merci.

56
Jake

C'est une excellente question et j'ai été surpris de voir à quel point il était difficile de trouver une réponse claire et complète. La plupart des réponses que j'ai trouvées étaient soit du code Sudo, soit non complètes à 100%.

J'ai été en mesure de créer une solution complète pour copier et enregistrer les données de mon DataGridView dans un fichier Excel basé sur la réponse de Jake. Je publie donc ma solution complète dans l'espoir d'aider d'autres nouveaux venus à c # comme moi :)

Tout d’abord, vous aurez besoin de la référence Microsoft.Office.Interop.Excel dans votre projet. Voir MSDN pour savoir comment l’ajouter.

Mon code:

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

Je n'avais pas l'intention de voler la réponse de @Jake et @ Cornelius, alors j'ai essayé de la modifier. mais cela a été rejeté. Quoi qu'il en soit, la seule amélioration que je dois signaler concerne l’évitement des colonnes vierges supplémentaires dans Excel après collage. L'ajout d'une ligne dataGridView1.RowHeadersVisible = false; masque ce que l'on appelle "En-tête de ligne" qui apparaît dans la partie gauche de DataGridView. Il n'est donc pas sélectionné et copié dans le Presse-papiers lorsque vous faites 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);          
    }
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());
    }
}
6
Koray

Le mieux est d’utiliser use 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();
3
Taran

L'interopérabilité est lente et pose d'autres problèmes, l'utilisation du presse-papiers ne semble pas extensible. Voici deux autres façons de le faire

  1. Travaillez directement avec les fichiers Excel 2007+ au lieu de travailler avec Excel, ce sera beaucoup (beaucoup) plus rapide. Vous pouvez utiliser OpenXML ( http://openxmldeveloper.org/ ), qui est le SDK de Microsoft. La meilleure façon d'apprendre OpenXML est de télécharger l'outil de productivité ( http://www.Microsoft.com/en-us/download/details.aspx?id=5124) , il prend un fichier existant et génère le code. nécessaire pour le créer. Une autre option, peut-être plus simple, consiste à utiliser ClosedXML ( http://closedxml.codeplex.com/ ). Cela semble beaucoup plus facile à utiliser (voir l'exemple http://closedxml.codeplex.com/wikipage?title=Showcase&referringTitle=Home ), mais je n'ai aucune expérience de ce logiciel. Je suis sûr qu'il existe d'autres bibliothèques qui fonctionnent avec Excel.

  2. Travailler avec Excel via OLEDB. Cela vous permet de travailler avec Excel comme s'il s'agissait d'une base de données. Voir http://www.codeproject.com/Articles/8500/Reading-and-Writing-Excel-using-OLEDB ou Performances d'OLEDB à lire Excel pour des exemples et plus de détails.

Je commencerais par ClosedXML.

3
Vadim

J'aime la solution de Jake. Le problème sans en-tête est résolu en procédant comme suit

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

bien sûr, cela ne fonctionne que si vous savez ce que les en-têtes doivent être à l’avance. 

2
jlh3302

c'est ce que j'utilise pour ma grille, essayez de l'utiliser pour les données de l'année, cela fonctionne parfaitement 

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

Cette réponse concerne pour la première question, pourquoi cela prend autant de temps et offre une solution alternative pour exporter le DataGridView vers Excel. 

MS Office Interop est lent et même Microsoft ne recommande pas l'utilisation d'Interop sur le serveur et ne peut pas être utilisé pour exporter des fichiers Excel volumineux. Pour plus de détails, voir pourquoi ne pas utiliser OLE Automation du point de vue de Microsoft.

Interop enregistre les fichiers Excel au format XLS (ancien format de fichier Excel 97-2003) et la prise en charge d'Office 2003 est terminée. Microsoft Excel a publié le format de fichier XLSX avec Office 2007 et recommande l’utilisation du SDK OpenXML au lieu d’Interop. Mais les fichiers XLSX ne sont pas si rapides et ne gèrent pas très bien les gros fichiers Excel car ils sont basés sur le format de fichier XML. C'est pourquoi Microsoft a également publié le format de fichier XLSB avec Office 2007, format de fichier recommandé pour les fichiers Excel volumineux. C'est un format binaire. La solution la plus rapide et la meilleure consiste donc à enregistrer les fichiers XLSB.

Vous pouvez utiliser cette bibliothèque Excel C # pour enregistrer des fichiers XLSB, mais elle prend également en charge les formats de fichier XLS et XLSX. 

Voir l'exemple de code suivant comme alternative à l'exportation de DataGridView vers 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");

Si vous devez également exporter le formatage de DataGridView, consultez cet exemple de code pour savoir comment exporter des données datagridview vers Excel en C # .

1
alex.pulver

Cette ligne ne fonctionne que pour le contrôle DataGridView sous Windows Forms:

DataObject dataObj = dataGridView1.GetClipboardContent();

Celui-ci répond au même problème, mais pour le contrôle DataGrid pour le framework WPF:

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