rango - recorrer excel c#
Escribir matriz en el rango de Excel (7)
Actualmente estoy tratando de escribir datos de una matriz de objetos en un rango en Excel usando el siguiente código, donde objData
es solo 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;
Esto casi funciona, el problema es que el rango se llena pero cada celda obtiene el valor del primer elemento en el objData
.
Los trabajos inversos, 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;
Devolvería una matriz que contiene todos los valores de la hoja de trabajo, por lo que no estoy seguro de por qué la lectura y la asignación funcionan de manera diferente.
¿Alguien ha hecho esto con éxito? Actualmente estoy escribiendo la matriz celda por celda, pero tiene que lidiar con lotes (> 50,000) de filas y esto consume mucho tiempo.
El tipo de definición de matriz parece ser la clave: en mi caso se trata de una matriz de una dimensión de 17 elementos que deben convertirse en una matriz de dos dimensiones
Definición para columnas: objeto [,] Matriz = objeto nuevo [17, 1];
Definición para el objeto rows [,] Array = new object [1,17];
El código para value2 es en ambos casos el mismo Excel.Range cell = activeWorksheet.get_Range (Range); cell.Value2 = Matriz;
LG Georg
En mi caso, el programa consulta la base de datos que devuelve un DataGridView. Luego copio eso en una matriz. Obtengo el tamaño de la matriz recién creada y luego escribo la matriz en 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)
{
//...
}
Este es un extracto del método mío, que convierte una DataTable (la variable dt) en una matriz y luego escribe la matriz en un rango en una hoja de cálculo (wsh var). También puede cambiar la variable topRow por la fila en la que desee colocar la matriz de cadenas.
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, no necesita usar una DataTable intermedia como yo, el extracto del código es solo para demostrar cómo una matriz se puede escribir en la hoja de trabajo en una sola llamada.
Gracias por los chicos de punteros: el argumento Value vs Value2 me dio un conjunto diferente de resultados de búsqueda que me ayudaron a darme cuenta de cuál es la respuesta. A propósito, la propiedad Value es una propiedad parametrizada, a la que se debe acceder a través de un descriptor de acceso en C #. Estos se llaman get_Value y set_Value, y toman un valor enum opcional. Si alguien está interesado, esto lo explica muy bien .
Sin embargo, es posible realizar la asignación a través de la propiedad Value2, que es preferible ya que la documentación de interoperabilidad recomienda el uso de los métodos get_Value y set_Value, por razones que no entiendo.
La clave parece ser la dimensión de la matriz de objetos. Para que la llamada funcione, la matriz debe declararse como bidimensional, incluso si solo está asignando datos unidimensionales.
Decidí que mi matriz de datos era un object[NumberofRows,1]
y la llamada de asignación funcionó.
Por alguna razón, la conversión a una matriz bidimensional no funcionó para mí. Pero el siguiente enfoque hizo:
public void SetRow(Range range, string[] data)
{
range.get_Resize(1, data.Length).Value2 = data;
}
Puede poner sus datos en un conjunto de registros y usar el método CopyFromRecordset de Excel, es mucho más rápido que rellenar celda por celda.
Puede crear un conjunto de registros a partir de un conjunto de datos utilizando este código . Tendrá que hacer algunas pruebas para ver si usar este método es más rápido que lo que está haciendo actualmente.
cuando quiere escribir un 1D Array en una hoja de Excel, tiene que transponerlo y no tiene que crear un arreglo 2D con 1 columna ([n, 1]) como leí arriba. Aquí hay un ejemplo de código:
wSheet.Cells(RowIndex, colIndex).Resize(RowsCount, ).Value = _excel.Application.transpose(My1DArray)
Que tengas un buen día, Gilles