2009-02-09 3 views
30

Ich möchte eine Zelle in einer Tabelle, die von einem Diagramm verwendet wird, mit dem Open XML SDK 2.0 (CTP) aktualisieren. Alle Code-Beispiele, die ich gefunden habe, fügen neue Zellen ein. Ich kämpfe mit dem Abrufen des richtigen Arbeitsblattes.Open XML SDK 2.0 - Wie aktualisiert man eine Zelle in einer Tabelle?

Wenn ich in Visual Studio durch den Baum navigiere, sehe ich drei Blätter, aber keine von ihnen hat Kinder. Was vermisse ich?

+1

Ich mache Fortschritte. Eine Sache, die mich stupste, war, dass alle Beispiele davon ausgehen, dass WorksheetParts.First() das Arbeitsblatt "Sheet1" erhält. Dies ist nicht der Fall, es gibt vielmehr zurück, was das erste Element in workbook.xml ist. Ich werde den Code veröffentlichen, wenn es funktioniert. – cdonner

+0

versuchen WorksheetParts .First(). Es wird das erste Element vom Typ Sheet erhalten. –

Antwort

60

Hier ist der Arbeitscode. Dies ist ein Prototyp. Bei einer größeren Anzahl von Änderungen könnte das Dokument nur einmal geöffnet werden. Außerdem gibt es einige fest codierte Dinge wie den Blattnamen und den Zelltyp, die parametrisiert werden müssten, bevor dies als produktionsbereit bezeichnet werden kann. http://openxmldeveloper.org/forums/4005/ShowThread.aspx war sehr hilfreich.

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

Danke für den Arbeitscode ... Ich konnte es leicht an meine Situation anpassen. Sie haben recht, die meisten Beispiele erstellen neue Arbeitsmappen/Arbeitsblätter und Zellen. Ich möchte nur einige existierende Zellen aktualisieren. –

+2

Wenn ich Ihren (ausgezeichneten) Beispielcode verwende, erhalte ich das beabsichtigte Ergebnis, aber wenn ich die XLSX-Datei in Excel 2010 öffne (nicht mit 2007 getestet), bekomme ich eine Warnung, dass etwas nicht stimmt (Excel fand nicht lesbaren Inhalt) und bietet an, es zu reparieren. Ich frage mich, ob das mit diesem Code verwandt ist, den Text nicht zuerst in die Zeichenfolge-Tabelle einzufügen. Wie würde ich diesen Code ändern, um die Warnung zu beseitigen? –

+0

Ich kann keine Hilfe mit Office 2010 anbieten, Philipp. Ich habe das seit Jahren nicht mehr gesehen. – cdonner

6

Ich habe mit Excel und fanden diese Helfer Bibliothek arbeitet eine große Hilfe zu sein (ich meine eigenen Helfer für Wort erstellt haben, hätte mindestens 2 Wochen gespeichert, wenn ich dies bewusst war): http://simpleooxml.codeplex.com/

Dies ist, was Zelle zu aktualisieren ist erforderlich (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 all diese Arbeit, um wirklich nützliche Methoden wie 'PasteText' zu erstellen und dann erstellen Sie nicht einmal einen einfachen Artikel um es zu verwenden. Zumindest haben wir MSDN aber trotzdem sind wir auf ooxml 2.5 da sollte mehr auf diesen Edelsteinen sein! =) – Coops

+0

Danke, das macht mir das Leben leichter! – GeorgDangl

3

die von @CDonner posted-Code einige Ausnahmen auslöst, ich habe einige der Code hinzugefügt, die werde auf Code achten, der eine Exception wirft, hier ich t ist

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

check string.Compare (cell.CellReference.Value, cellReference, true)> 0), da es "AA9" <"B9" gibt, was hinsichtlich der Excelsäulenpriorität falsch ist – avestnik

1

Dies ist SDK 2.5 allerdings war jedoch sehr nützlich Code hier: http://fczaja.blogspot.dk/2013/05/how-to-read-and-write-excel-cells-with.html

benötigte eine leichte Modifikation für Textwerte zu tun, um füge sie die 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; 
} 

Und es wie folgt verwenden:

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

Ich habe einige Änderungen an @AZ Code.

Zunächst gibt es bei der GetCell-Funktion ein Problem bei der Auswahl der aktuellen Zeile. Ändern Sie einfach:

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

statt:

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

Und im Abschnitt:

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

Wenn Sie Spalten oben Z Spalte verwenden (als AA-Säule, zum Beispiel) nicht richtig funktionieren. Zu einigen benutze ich die Spaltennummern, um zu bestimmen, wo die Zelle eingefügt wird.

Dazu habe ich eine Funktion Column, die Spaltenbuchstaben Zahlen mit convert:

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; 
    } 

Also änderte ich die String-Funktion für diese vergleichen:

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; 
       } 
      } 

Mit freundlichen Grüßen.

Verwandte Themen