2009-02-09 7 views
30

Je souhaite mettre à jour une cellule dans une feuille de calcul utilisée par un graphique, à l'aide de Open XML SDK 2.0 (CTP). Tous les exemples de code que j'ai trouvés insèrent de nouvelles cellules. Je me bats avec la récupération de la bonne feuille de calcul. Lorsque je navigue dans l'arborescence de Visual Studio, je vois trois feuilles, mais aucune d'entre elles n'a d'enfants. Qu'est-ce que je rate?Open XML SDK 2.0 - comment mettre à jour une cellule dans une feuille de calcul?

+1

Je fais des progrès. Une chose qui m'a stupéfié était que tous les exemples supposent que WorksheetParts.First() vous obtient la feuille de calcul "Sheet1". Ce n'est pas le cas, il renvoie plutôt tout ce qui est le premier élément dans le fichier workbook.xml. Je vais poster le code quand je l'ai fonctionné. – cdonner

+0

try WorksheetParts .First(). Il obtiendra le premier élément qui est le type de feuille. –

Répondre

60

Voici le code de travail. C'est un prototype. Pour un plus grand nombre de modifications, il se peut que vous n'ouvriez le document qu'une seule fois. De plus, il y a des choses codées en dur comme le nom de la feuille et le type de cellule qui devraient être paramétrés avant que cela puisse être appelé prêt pour la production. http://openxmldeveloper.org/forums/4005/ShowThread.aspx était très utile.

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Linq; 
using System.Text; 
using DocumentFormat.OpenXml; 
using DocumentFormat.OpenXml.Packaging; 
using DocumentFormat.OpenXml.Spreadsheet; 
using System.Xml; 
using System.IO; 
using System.Diagnostics; 

namespace OpenXMLWindowsApp 
{ 
    public class OpenXMLWindowsApp 
    { 
     public void UpdateSheet() 
     { 
      UpdateCell("Chart.xlsx", "20", 2, "B"); 
      UpdateCell("Chart.xlsx", "80", 3, "B"); 
      UpdateCell("Chart.xlsx", "80", 2, "C"); 
      UpdateCell("Chart.xlsx", "20", 3, "C"); 

      ProcessStartInfo startInfo = new ProcessStartInfo("Chart.xlsx"); 
      startInfo.WindowStyle = ProcessWindowStyle.Normal; 
      Process.Start(startInfo); 
     } 

     public static void UpdateCell(string docName, string text, 
      uint rowIndex, string columnName) 
     { 
      // Open the document for editing. 
      using (SpreadsheetDocument spreadSheet = 
        SpreadsheetDocument.Open(docName, true)) 
      { 
       WorksheetPart worksheetPart = 
         GetWorksheetPartByName(spreadSheet, "Sheet1"); 

       if (worksheetPart != null) 
       { 
        Cell cell = GetCell(worksheetPart.Worksheet, 
              columnName, rowIndex); 

        cell.CellValue = new CellValue(text); 
        cell.DataType = 
         new EnumValue<CellValues>(CellValues.Number); 

        // Save the worksheet. 
        worksheetPart.Worksheet.Save(); 
       } 
      } 

     } 

     private static WorksheetPart 
      GetWorksheetPartByName(SpreadsheetDocument document, 
      string sheetName) 
     { 
      IEnumerable<Sheet> sheets = 
       document.WorkbookPart.Workbook.GetFirstChild<Sheets>(). 
       Elements<Sheet>().Where(s => s.Name == sheetName); 

      if (sheets.Count() == 0) 
      { 
       // The specified worksheet does not exist. 

       return null; 
      } 

      string relationshipId = sheets.First().Id.Value; 
      WorksheetPart worksheetPart = (WorksheetPart) 
       document.WorkbookPart.GetPartById(relationshipId); 
      return worksheetPart; 

     } 

     // Given a worksheet, a column name, and a row index, 
     // gets the cell at the specified column and 
     private static Cell GetCell(Worksheet worksheet, 
        string columnName, uint rowIndex) 
     { 
      Row row = GetRow(worksheet, rowIndex); 

      if (row == null) 
       return null; 

      return row.Elements<Cell>().Where(c => string.Compare 
        (c.CellReference.Value, columnName + 
        rowIndex, true) == 0).First(); 
     } 


     // Given a worksheet and a row index, return the row. 
     private static Row GetRow(Worksheet worksheet, uint rowIndex) 
     { 
      return worksheet.GetFirstChild<SheetData>(). 
       Elements<Row>().Where(r => r.RowIndex == rowIndex).First(); 
     } 
    } 
} 
+1

Merci pour le code de travail ... J'ai facilement pu l'adapter à ma situation. Vous avez raison, la plupart des exemples créent de nouveaux classeurs/feuilles de travail et cellules. Je veux juste mettre à jour certaines cellules existantes. –

+2

Lorsque j'utilise votre (excellent) exemple de code j'obtenir le résultat escompté, mais quand j'ouvre le fichier XLSX dans Excel 2010 (n'ont pas testé avec 2007) Je reçois un avertissement que quelque chose n'est pas tout à fait raison (Excel a trouvé du contenu undreadable) et propose de le réparer. Je me demande si c'est lié à ce code n'insérer le texte dans la table de première chaîne. Comment modifier ce code pour éliminer l'avertissement? –

+0

Je ne peux pas offrir d'aide avec Office 2010, Philipp. Je n'ai pas regardé ça depuis des années. – cdonner

6

Je travaille avec Excel et trouvé cette bibliothèque d'assistance pour être d'une grande aide (je l'ai créé mes propres aides pour mot, aurait sauvé au moins 2 semaines si je le savais): http://simpleooxml.codeplex.com/

C'est ce qui est nécessaire pour mettre à jour la cellule (writer.PasteText (...)):

MemoryStream stream = SpreadsheetReader.Create(); 
SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true); 
WorksheetPart worksheetPart = SpreadsheetReader.GetWorksheetPartByName(doc, "Sheet1"); 
WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart); 

writer.PasteText("B2", "Hello World"); 

//Save to the memory stream 
SpreadsheetWriter.Save(doc); 

byte[] result = stream.ToArray(); 
FileStream file = new FileStream(@"D:\x1.xlsx", FileMode.Create); 
file.Write(result, 0, result.Length); 
file.Close(); 
+0

Microsoft fait tout ce travail pour créer des méthodes vraiment utiles telles que 'PasteText' et ne crée pas même un simple article autour de l'utiliser. Au moins, nous avons MSDN mais nous sommes encore sur Ooxml 2.5 il devrait y avoir plus sur ces gemmes! =) – Coops

+0

Merci, cela me facilite la vie! – GeorgDangl

3

le code publié par @CDonner jette quelques exceptions près, j'ai ajouté une partie du code qui prendra soin du code, ce qui jette une exception, ici je t est

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Linq; 
using System.Text; 
using DocumentFormat.OpenXml; 
using DocumentFormat.OpenXml.Packaging; 
using DocumentFormat.OpenXml.Spreadsheet; 
using System.Xml; 
using System.IO; 
using System.Diagnostics; 

namespace Application.Model{ 
public class TempCode 
{ 
    public TempCode() 
    { 
     UpdateCell("E:/Visual Studio Code/Book1.xlsx", "120", 1, "A"); 
     UpdateCell("E:/Visual Studio Code/Book1.xlsx", "220", 2, "B"); 
     UpdateCell("E:/Visual Studio Code/Book1.xlsx", "320", 3, "C"); 
     UpdateCell("E:/Visual Studio Code/Book1.xlsx", "420", 4, "D"); 
     UpdateCell("E:/Visual Studio Code/Book1.xlsx", "520", 5, "E"); 

     ProcessStartInfo startInfo = new ProcessStartInfo("E:/Visual Studio Code/Book1.xlsx"); 
     startInfo.WindowStyle = ProcessWindowStyle.Normal; 
     Process.Start(startInfo); 



    } 

    public static void UpdateCell(string docName, string text,uint rowIndex, string columnName){ 
     // Open the document for editing. 
     using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true)) 
     { 
      WorksheetPart worksheetPart = GetWorksheetPartByName(spreadSheet, "Sheet2"); 
      if (worksheetPart != null) 
      { 
       Cell cell = GetCell(worksheetPart.Worksheet, columnName, rowIndex); 
       cell.CellValue = new CellValue(text); 
       cell.DataType = new EnumValue<CellValues>(CellValues.Number); 
       // Save the worksheet. 
       worksheetPart.Worksheet.Save(); 
      } 
     } 

    } 

    private static WorksheetPart GetWorksheetPartByName(SpreadsheetDocument document, string sheetName){ 
     IEnumerable<Sheet> sheets =document.WorkbookPart.Workbook.GetFirstChild<Sheets>(). 
         Elements<Sheet>().Where(s => s.Name == sheetName); 
     if (sheets.Count() == 0){ 
      return null; 
     } 
     string relationshipId = sheets.First().Id.Value; 
     WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId); 
     return worksheetPart; 
    } 


    private static Cell GetCell(Worksheet worksheet, string columnName, uint rowIndex) 
    { 
     Row row; 
     string cellReference = columnName + rowIndex; 
     if (worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0) 
      row = worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault(); 
     else{ 
      row = new Row() { RowIndex = rowIndex }; 
      worksheet.Append(row); 
     } 

     if (row == null) 
      return null; 

     if (row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).Count() > 0) { 
      return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First(); 
     } 
     else{ 
      Cell refCell = null; 
      foreach (Cell cell in row.Elements<Cell>()){ 
       if (string.Compare(cell.CellReference.Value, cellReference, true) > 0){ 
        refCell = cell; 
        break; 
       } 
      } 
      Cell newCell = new Cell() { 
       CellReference = cellReference, 
       StyleIndex = (UInt32Value)1U 

      }; 
      row.InsertBefore(newCell, refCell); 
      worksheet.Save(); 
      return newCell; 
     } 
    } 
} 

}

+0

chèque string.Compare (cell.CellReference.Value, CellReference, true)> 0) car il donne "AA9" < "B9" ce qui est faux en termes d'Excel colonne priorité – avestnik

1

C'est SDK 2.5 si, cependant, était code très utile trouvé ici: http://fczaja.blogspot.dk/2013/05/how-to-read-and-write-excel-cells-with.html

nécessaire de faire une légère modification des valeurs de texte pour les ajouter à la SharedStringTablePart.

// Given text and a SharedStringTablePart, creates a SharedStringItem with the specified text 
// and inserts it into the SharedStringTablePart. If the item already exists, returns its index. 
private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart) 
{ 
    // If the part does not contain a SharedStringTable, create one. 
    if (shareStringPart.SharedStringTable == null) 
    { 
     shareStringPart.SharedStringTable = new SharedStringTable(); 
    } 

    int i = 0; 

    // Iterate through all the items in the SharedStringTable. If the text already exists, return its index. 
    foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>()) 
    { 
     if (item.InnerText == text) 
     { 
      return i; 
     } 

     i++; 
    } 

    // The text does not exist in the part. Create the SharedStringItem and return its index. 
    shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new Text(text))); 
    shareStringPart.SharedStringTable.Save(); 

    return i; 
} 

Et l'utiliser comme ceci:

SharedStringTablePart shareStringPart = GetSharedStringTablePart(excelDoc); 

// Insert the text into the SharedStringTablePart. 
int index = InsertSharedStringItem(cellValue, shareStringPart); 

// Set the value of cell A1. 
cell.CellValue = new CellValue(index.ToString()); 
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString); 
0

J'ai fait quelques modifications sur le code @AZ. En premier lieu, la fonction GetCell pose un problème lors de la sélection de la ligne en cours. Il suffit de changer:

if (worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0) 

au lieu de:

if (worksheet.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0) 

Et dans la section:

if (string.Compare(cell.CellReference.Value, cellReference, true) > 0) 

Si vous utilisez des colonnes ci-dessus Z colonne (comme colonne AA, par exemple) ne travaille correctement. Pour certains cela, j'utilise les numéros de colonnes pour déterminer où insérer la cellule.

Pour cela, je créé une ColumnIndex fonction, avec convertir les lettres de colonnes pour les numéros:

private static int ColumnIndex(string reference) 
    { 
     int ci = 0; 
     reference = reference.ToUpper(); 
     for (int ix = 0; ix < reference.Length && reference[ix] >= 'A'; ix++) 
      ci = (ci * 26) + ((int)reference[ix] - 64); 
     return ci; 
    } 

Je changé la chaîne fonction de comparaison pour cela:

string columnNew = new String(cellReference.Where(c => c != '-' && (c < '0' || c > '9')).ToArray()); 
      foreach (Cell cell in row.Elements<Cell>()) 
      { 
       string columnBase = new String(cell.CellReference.Value.Where(c => c != '-' && (c < '0' || c > '9')).ToArray()); 

       if (ColumnIndex(columnBase) > ColumnIndex(columnNew)) 
       { 
        refCell = cell; 
        break; 
       } 
      } 

Cordialement.

Questions connexes