Write Array to Excel Range

Thanks for the pointers guys - the Value vs Value2 argument got me a different set of search results which helped me realise what the answer is. Incidentally, the Value property is a parametrized property, which must be accessed through an accessor in C#. These are called get_Value and set_Value, and take an optional enum value. If anyone's interested, this explains it nicely.

It's possible to make the assignment via the Value2 property however, which is preferable as the interop documentation recommends against the use use of the get_Value and set_Value methods, for reasons beyond my understanding.

The key seems to be the dimension of the array of objects. For the call to work the array must be declared as two-dimensional, even if you're only assigning one-dimensional data.

I declared my data array as an object[NumberofRows,1] and the assignment call worked.


This is an excerpt from method of mine, which converts a DataTable (the dt variable) into an array and then writes the array into a Range on a worksheet (wsh var). You can also change the topRow variable to whatever row you want the array of strings to be placed at.

object[,] arr = new object[dt.Rows.Count, dt.Columns.Count];
for (int r = 0; r < dt.Rows.Count; r++)
{
    DataRow dr = dt.Rows[r];
    for (int c = 0; c < dt.Columns.Count; c++)
    {
        arr[r, c] = dr[c];
    }
}
Excel.Range c1 = (Excel.Range)wsh.Cells[topRow, 1];
Excel.Range c2 = (Excel.Range)wsh.Cells[topRow + dt.Rows.Count - 1, dt.Columns.Count];
Excel.Range range = wsh.get_Range(c1, c2);
range.Value = arr;

Of course you do not need to use an intermediate DataTable like I did, the code excerpt is just to demonstrate how an array can be written to worksheet in single call.


In my case, the program queries the database which returns a DataGridView. I then copy that to an array. I get the size of the just created array and then write the array to an Excel spreadsheet. This code outputs over 5000 lines of data in about two seconds.

//private System.Windows.Forms.DataGridView dgvResults;
dgvResults.DataSource = DB.getReport();

Microsoft.Office.Interop.Excel.Application oXL;
Microsoft.Office.Interop.Excel._Workbook oWB;
Microsoft.Office.Interop.Excel._Worksheet oSheet;
try
{
    //Start Excel and get Application object.
    oXL = new Microsoft.Office.Interop.Excel.Application();
    oXL.Visible = true;

    oWB = (Microsoft.Office.Interop.Excel._Workbook)(oXL.Workbooks.Add(""));
    oSheet = (Microsoft.Office.Interop.Excel._Worksheet)oWB.ActiveSheet;

    var dgArray = new object[dgvResults.RowCount, dgvResults.ColumnCount+1];
    foreach (DataGridViewRow i in dgvResults.Rows)
    {
        if (i.IsNewRow) continue;
        foreach (DataGridViewCell j in i.Cells)
        {
            dgArray[j.RowIndex, j.ColumnIndex] = j.Value.ToString();
        }
    }

    Microsoft.Office.Interop.Excel.Range chartRange;

    int rowCount = dgArray.GetLength(0);
    int columnCount = dgArray.GetLength(1);
    chartRange = (Microsoft.Office.Interop.Excel.Range)oSheet.Cells[2, 1]; //I have header info on row 1, so start row 2
    chartRange = chartRange.get_Resize(rowCount, columnCount);
    chartRange.set_Value(Microsoft.Office.Interop.Excel.XlRangeValueDataType.xlRangeValueDefault, dgArray);


    oXL.Visible = false;
    oXL.UserControl = false;
    string outputFile = "Output_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xlsx";

    oWB.SaveAs("c:\\temp\\"+outputFile, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing,
        false, false, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange,
        Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    oWB.Close();
}
catch (Exception ex)
{
    //...
}

Tags:

C#

Interop

Excel