Actualmente estoy tratando de escribir los datos de un array de objetos a un rango en Excel utilizando el siguiente código, donde objData es simplemente una matriz de cadenas:

private object m = System.Type.Missing;
object[] objData = getDataIWantToWrite();

Range rn_Temp;
rn_Temp = (Range)XlApp.get_Range(RangeName, m);
rn_Temp = rn_Temp.get_Resize(objData.GetUpperBound(), 1);
rn_Temp.value2 = objData;

Esta muy cerca de las obras, el problema es que el abanico se va llenando, pero cada célula obtiene el valor del primer elemento de la objData.

La inversa funciona, es decir,

private object m = System.Type.Missing;
object[] objData = new object[x,y]

Range rn_Temp;
rn_Temp = (Range)XlApp.get_Range(RangeName, m);
rn_Temp = rn_Temp.get_Resize(objData.GetUpperBound(), 1);
objData = (object[])rn_Temp.value2;

le devuelva una matriz que contiene todos los valores de la hoja de cálculo, así que no estoy seguro de por qué la lectura y la asignación de trabajo de manera diferente.

¿Alguien ha hecho esto correctamente? Actualmente estoy escribiendo la matriz de la célula por célula, pero tiene que lidiar con un montón (>50.000) de filas y este es, por tanto, requieren de mucho tiempo.

  • La respuesta seleccionada no hacen evidentes de inmediato, así que si alguien tiene alguna vez este problema, en definitiva, la solución es que usted necesita para asignar una matriz 2D (object[,]) aunque los datos podría caber en sólo una dimensión.
  • muy útil
InformationsquelleAutor Jon Artus | 2009-02-11

8 Comentarios

  1. 90

    Esto es un extracto del método de la mía, que convierte un DataTable (el dt variable) en una matriz y, a continuación, escribe la matriz en una Range en una hoja de cálculo (wsh var). También puede cambiar el topRow variable a lo que la fila que desea que el conjunto de cadenas para ser colocado en.

    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;

    Por supuesto, usted no necesita usar un intermedio DataTable como lo hice yo, el extracto de código es solo para demostrar cómo una matriz puede ser escrito en la hoja de cálculo en una sola llamada.

    • Muy interesante – que es exactamente lo que quiero hacer, pero no puedo acceder a la propiedad Value del objeto range – sólo puedo acceder Valor2, y creo que puede ser el problema. ¿Alguna idea de cómo puedo acceder a el Valor de la propiedad? Lo interops estás usando?
    • Importados de Excel del tipo de biblioteca (pasa a ser de Office 2003 en mi caso). I. e., No estoy utilizando los ensamblados de interoperabilidad primarios. Acabo de añadir la referencia a la COM de Excel tlb en el VS. Ahora no recuerdo exactamente el motivo para la no utilización de la Pia, aunque.
    • Yo uso la gama.set_Value(Faltan.Valor, objectArray ); Usted necesita para asegurarse de que la matriz tiene el mismo tamaño que el rango.
    • Esto depende de la versión de Office para que el interops son importados. Yo estaba usando Office 2000 (no 2003 como dije en el comentario anterior) en la que el Valor de la propiedad no tiene parámetros opcionales. Tiene un parámetro opcional en TLBs a partir de la versión 2003, lo que la propiedad se traduce en un
    • método, puesto que las propiedades no puede tener parámetros en C#.
    • En C# 4.0, hay propiedades indizadas, consulte blogs.msdn.com/kirillosenkov/archive/2009/10/20/…
    • Alguna idea de por qué esto arroja una COMException al intentar copiar una columna uniqueidentifier cuando se utiliza una matriz de objetos, sino una matriz de cadena parece manejar bien?
    • Tuve que usar Excel.Rango rango = wsh.Rango[c1, c2]; rango.Valor2 = arr;
    • Gran esto funciona, pero puedo capaces de escribir los datos de uso por encima de la lógica, pero si puedo aplicar el filtro en la hoja y tratar de escribir los datos de uso por encima de la lógica de los valores de la primera de las columnas de escritura de datos en todas las columnas, obteniendo como resultado que no se esperaba.

  2. 10

    Gracias por los consejos chicos, el Valor de vs Valor2 argumento me tiene un conjunto diferente de los resultados de la búsqueda que me ayudó a darse cuenta de cuál es la respuesta. Por cierto, el Valor de la propiedad es una parametrización de la propiedad, que debe acceder a través de un descriptor de acceso en C#. Estos son los llamados get_Value y set_Value, y tomar un opcional el valor de enumeración. Si alguien está interesado, esto lo explica muy bien.

    Es posible realizar la asignación a través de la propiedad Value2 sin embargo, que es preferible, como la interoperabilidad de la documentación recomienda contra el uso de la get_Value y set_Value métodos, por razones más allá de mi entendimiento.

    La clave parece ser la dimensión de la matriz de objetos. Para la llamada a la matriz debe ser declarada como de dos dimensiones, incluso si usted es sólo la asignación de datos unidimensional.

    Declaré mi matriz de datos como un object[NumberofRows,1] y la asignación de la llamada trabajado.

    • gracias, se ve como una 1D array, siempre se escribe horiztonally (incluso con un rango vertical, en cuyo caso se escribe el primer elemento en varias ocasiones). para obtener una matriz a escribir verticalmente, debe hacer lo que usted dijo y que se haga una [n, 1] matriz. muchas gracias porque yo probablemente nunca habría descubierto a mí mismo.
  3. 4

    Usted podría poner sus datos en un conjunto de registros y el uso Excel Método CopyFromRecordset – es mucho más rápido que rellenar celda por celda.

    Puede crear un conjunto de registros de un conjunto de datos utilizando este código. Usted tendrá que hacer algunas pruebas para ver si el uso de este método es más rápido que lo que están haciendo en la actualidad.

    • Esto puede ser una pregunta tonta, pero ¿dónde puedo encontrar un conjunto de registros de clase en C#? O sabes por casualidad si existe otra clase que me puede pasar en la cual va a trabajar? Muchas gracias!
    • Agregar la referencia a la asamblea de ADODB versión 7.0.3300.0. usando ADODB; ADODB es de tipo «Recordset»
  4. 3

    En mi caso, el programa de consulta de la base de datos que devuelve un DataGridView. Yo, a continuación, copiarlo a una matriz. Puedo obtener el tamaño de la recién creada matriz y, a continuación, escribir la matriz a una hoja de cálculo de Excel. Este código genera más de 5000 líneas de datos en aproximadamente dos segundos.

    //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)
    {
    //...
    }
  5. 2

    cuando se desea escribir un 1D Matriz en una hoja de Excel usted tiene para su incorporación y usted no tiene que crear una matriz 2D con 1 columna ([n, 1]) como he leído arriba! Aquí es un ejemplo de código :

     wSheet.Cells(RowIndex, colIndex).Resize(RowsCount, ).Value = _excel.Application.transpose(My1DArray)

    Tener un buen día,
    Gilles

    • muy útil la información, gracias a usted!
  6. 1

    Por alguna razón, la conversión a una matriz de 2 dimensiones no funciona para mí. Pero el siguiente enfoque: a

    public void SetRow(Range range, string[] data)
    {
    range.get_Resize(1, data.Length).Value2 = data;
    }
  7. 1

    El tipo de definición de la matriz parece la clave:
    En mi caso es una matriz de una dimensión de 17 de elementos que tienen que convertir a una matriz de dos dimensiones

    Definición de las columnas:
    objeto[,] Array = new object[17, 1];

    Definición de filas
    objeto[,] Array= new object[1,17];

    El código para valor2 trata en ambos casos de la misma
    Excel.Rango de celda = activeWorksheet.get_Range(Rango);
    de la célula.Valor2 = Array;

    LG Georg

  8. 1

    agregar ExcelUtility clase a su proyecto y disfrutar de ella.

    ExcelUtility.cs contenido del Archivo:

    using System;
    using Microsoft.Office.Interop.Excel;
    static class ExcelUtility
    {
    public static void WriteArray<T>(this _Worksheet sheet, int startRow, int startColumn, T[,] array)
    {
    var row = array.GetLength(0);
    var col = array.GetLength(1);
    Range c1 = (Range) sheet.Cells[startRow, startColumn];
    Range c2 = (Range) sheet.Cells[startRow + row - 1, startColumn + col - 1];
    Range range = sheet.Range[c1, c2];
    range.Value = array;
    }
    public static bool SaveToExcel<T>(T[,] data, string path)
    {
    try
    {
    //Start Excel and get Application object.
    var oXl = new Application {Visible = false};
    //Get a new workbook.
    var oWb = (_Workbook) (oXl.Workbooks.Add(""));
    var oSheet = (_Worksheet) oWb.ActiveSheet;
    //oSheet.WriteArray(1, 1, bufferData1);
    oSheet.WriteArray(1, 1, data);
    oXl.Visible = false;
    oXl.UserControl = false;
    oWb.SaveAs(path, XlFileFormat.xlWorkbookDefault, Type.Missing,
    Type.Missing, false, false, XlSaveAsAccessMode.xlNoChange,
    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
    oWb.Close(false);
    oXl.Quit();
    }
    catch (Exception e)
    {
    return false;
    }
    return true;
    }
    }

    uso :

    var data = new[,]
    {
    {11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
    {21, 22, 23, 24, 25, 26, 27, 28, 29, 30},
    {31, 32, 33, 34, 35, 36, 37, 38, 39, 40}
    };
    ExcelUtility.SaveToExcel(data, "test.xlsx");

    Saludos!

Dejar respuesta

Please enter your comment!
Please enter your name here