web-dev-qa-db-ja.com

ボタンをクリックしたときにdataGridViewデータをExcelに即座にエクスポートする方法は?

データグリッドビューに1万行と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(1万行)からExcelにエクスポートできますか?

これ以外に、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#が初めてです。

36
Jake

これを簡単なコピーアンドペースト方式で解決しました。これが最善の方法であるかどうかはわかりませんが、私にとっては、ほぼ瞬時にうまく機能します。これが私のコードです。

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

ありがとう。

63
Jake

これは素晴らしい質問であり、明確で完全な答えを見つけるのがどれほど難しいか驚きました。私が見つけた答えのほとんどは、Sudoコードであるか、100%完全ではありませんでした。

JGridの回答に基づいてDataGridViewからExcelファイルにデータをコピーして保存する完全なソリューションを作成できたので、他の新しいユーザーが自分のようなc#に役立つことを期待して、完全なソリューションを投稿しています:)

最初に、プロジェクトで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();
    }
}
25
Cornelius

@Jakeと@Corneliusの答えを盗むつもりはなかったので、編集してみました。しかし、それは拒否されました。とにかく、私が指摘しなければならない唯一の改善点は、貼り付け後にExcelで余分な空白列を避けることです。 dataGridView1.RowHeadersVisible = false;を1行追加すると、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);          
    }
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());
    }
}
7
Koray

最適な使用方法は、closedxml.codeplex.com Libraryを使用することです。Referit @ 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

相互運用は低速であり、他の問題もあります。クリップボードの使用は拡張できないようです。これを行うには、他に2つの方法があります

  1. Excelを使用する代わりに、Excel 2007+ファイルを直接使用すると、はるかに(はるかに)高速になります。 MicrosoftのSDKであるOpenXML( http://openxmldeveloper.org/ )を使用できます。 OpenXMLを学習する最良の方法は、生産性向上ツール( http://www.Microsoft.com/en-us/download/details.aspx?id=5124) をダウンロードすることです。既存のファイルを取得し、作成に必要なコードを生成します。もう1つの、おそらくより簡単なオプションは、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-OLEDB または Excelを読み取るOLEDBのパフォーマンス を参照してください詳細。

ClosedXMLから始めます。

3
Vadim

私はジェイクのソリューションが好きです。ヘッダーのない問題は、以下を実行することで解決されます

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

もちろん、これはヘッダーが事前に何であるかを知っている場合にのみ機能します。

3
jlh3302

それは私が私の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();
        }
1
Loubna H

この答えは最初の質問に対するものです。なぜそんなに時間がかかり、DataGridViewをExcelにエクスポートするための代替ソリューションを提供するのか。

MS Office Interopは低速であり、Microsoftでさえサーバー側でのInteropの使用を推奨しておらず、大きなExcelファイルのエクスポートには使用できません。詳細については、Microsoftの観点から OLE Automationを使用しない理由 を参照してください。

InteropはExcelファイルをXLSファイル形式(古いExcel 97-2003ファイル形式)で保存し、Office 2003のサポートは終了しました。 Microsoft Excelは、Office 2007でXLSXファイル形式をリリースしており、InteropではなくOpenXML SDKの使用を推奨しています。しかし、XLSXファイルはそれほど高速ではなく、XMLファイル形式に基づいているため、非常に大きなExcelファイルを処理できません。これが、MicrosoftがOffice 2007でXLSBファイル形式をリリースした理由です。これは、大きなExcelファイルに推奨されるファイル形式です。これはバイナリ形式です。したがって、最善かつ最速のソリューションは、XLSBファイルを保存することです。

この C#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の書式設定もエクスポートする必要がある場合は、このコードサンプルで C#でExcelにdatagridviewをエクスポート を確認してください。

1
alex.pulver

この行は、Windowsフォーム上のDataGridViewコントロールに対してのみ機能します。

DataObject dataObj = dataGridView1.GetClipboardContent();

これは同じ問題に対処しますが、WPFフレームワークのDataGridコントロールの場合:

    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

DataGridViewのRightToLeftYesに設定されている場合、データは逆にコピーされます。したがって、以下のコードを使用してデータを正しくコピーする必要があります。

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

代替 Excelは問題なくcsvファイルを解析できるため、Office dllを使用せずに高速エクスポートを実行できます。

次のようなことを行います(タイトルのある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
0
Caveman