web-dev-qa-db-fra.com

Écrire un tableau dans la plage Excel

J'essaie actuellement d'écrire des données à partir d'un tableau d'objets dans une plage dans Excel en utilisant le code suivant, où objData n'est qu'un tableau de chaînes:

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;

Cela fonctionne très bien, le problème étant que la plage est remplie mais chaque cellule obtient la valeur du premier élément dans le objData.

L'inverse fonctionne, c'est-à-dire.

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;

retournerait un tableau contenant toutes les valeurs de la feuille de calcul, donc je ne sais pas pourquoi la lecture et l'affectation fonctionnent différemment.

Quelqu'un a-t-il déjà réussi cela? J'écris actuellement le tableau cellule par cellule, mais il doit faire face à beaucoup (> 50 000) de lignes et cela prend donc beaucoup de temps.

50
Jon Artus

Ceci est un extrait de la mienne, qui convertit un DataTable (la variable dt) en un tableau, puis écrit le tableau dans une plage sur une feuille de calcul (wsh var). Vous pouvez également remplacer la variable topRow par la ligne sur laquelle vous souhaitez placer le tableau de chaînes.

        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;

Bien sûr, vous n'avez pas besoin d'utiliser un DataTable intermédiaire comme je l'ai fait, l'extrait de code consiste simplement à montrer comment un tableau peut être écrit dans une feuille de calcul en un seul appel.

86
petr k.

Merci pour les pointeurs, l'argument Valeur vs Valeur2 m'a donné un ensemble de résultats de recherche différent qui m'a aidé à réaliser la réponse. Par ailleurs, la propriété Value est une propriété paramétrée, qui doit être accessible via un accesseur en C #. Ceux-ci sont appelés get_Value et set_Value, et prennent une valeur d'énumération facultative. Si quelqu'un est intéressé, cela l'explique bien .

Il est cependant possible de faire l'affectation via la propriété Value2, ce qui est préférable car la documentation d'interopérabilité le déconseille d'utiliser les méthodes get_Value et set_Value, pour des raisons que je ne comprends pas.

La clé semble être la dimension du tableau d'objets. Pour que l'appel fonctionne, le tableau doit être déclaré comme bidimensionnel, même si vous n'affectez que des données unidimensionnelles.

J'ai déclaré mon tableau de données en tant que object[NumberofRows,1] et l'appel d'affectation a fonctionné.

9
Jon Artus

Vous pouvez mettre vos données dans un jeu d'enregistrements et utiliser méthode CopyFromRecordset d'Excel - c'est beaucoup plus rapide que de remplir cellule par cellule.

Vous pouvez créer un jeu d'enregistrements à partir d'un jeu de données en utilisant ce code . Vous devrez faire quelques essais pour voir si l'utilisation de cette méthode est plus rapide que ce que vous faites actuellement.

4
Galwegian

Dans mon cas, le programme interroge la base de données qui renvoie un DataGridView. Je copie ensuite cela dans un tableau. J'obtiens la taille du tableau que je viens de créer, puis j'écris le tableau dans une feuille de calcul Excel. Ce code génère plus de 5000 lignes de données en environ deux secondes.

//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)
{
    //...
}
3
Crazy Cat

lorsque vous voulez écrire un tableau 1D dans une feuille Excel vous devez le transposer et vous n'avez pas besoin de créer un tableau 2D avec 1 colonne ([n, 1]) comme je l'ai lu ci-dessus! Voici un exemple de code:

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

Passe une bonne journée, Gilles

2
Gilles5678

Le type de définition de tableau semble être la clé: dans mon cas, il s'agit d'un tableau à une dimension de 17 éléments qui doivent être convertis en tableau à deux dimensions

Définition des colonnes: objet [] Array = nouvel objet [17, 1];

Définition de l'objet lignes [] Tableau = nouvel objet [1,17];

Le code de value2 est dans les deux cas la même cellule Excel.Range = activeWorksheet.get_Range (Range); cell.Value2 = Array;

LG Georg

1
Georg

Pour une raison quelconque, la conversion en un tableau à 2 dimensions n'a pas fonctionné pour moi. Mais l'approche suivante l'a fait:

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