2012-06-20 15 views
33

Ich habe eine .xlsx-Kalkulationstabelle in C# mithilfe des OpenXML-SDK erstellt, kann aber nicht herausfinden, wie Zellstile funktionieren. Ich habe Dateien untersucht, die mit Excel erstellt wurden, und kann nicht wirklich herausfinden, wie das geht.Zellstile in OpenXML-Tabellenkalkulation (SpreadsheetML)

Gerade jetzt, Ich erstelle eine Füllung, ein CellStyleFormat zu schaffen, bei der Füllung weist ein CellFormat schaffen, die auf dem Index der CellStyleFormat Punkte, dann ein CellStyle schaffen, die auf die CellFormat verweist.

Hier ist der Code, den ich mit dem Dokument zu generieren:

Console.WriteLine("Creating document"); 
using (var spreadsheet = SpreadsheetDocument.Create("output.xlsx", SpreadsheetDocumentType.Workbook)) 
{ 
    Console.WriteLine("Creating workbook"); 
    spreadsheet.AddWorkbookPart(); 
    spreadsheet.WorkbookPart.Workbook = new Workbook(); 
    Console.WriteLine("Creating worksheet"); 
    var wsPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>(); 
    wsPart.Worksheet = new Worksheet(); 

    var stylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>(); 
    stylesPart.Stylesheet = new Stylesheet(); 
    stylesPart.Stylesheet.Fills = new Fills(); 

    // create a solid red fill 
    var solidRed = new PatternFill() { PatternType = PatternValues.Solid }; 
    solidRed.AppendChild(new BackgroundColor { Rgb = HexBinaryValue.FromString("FF00FF00") }); 

    stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill() { PatternType = PatternValues.None } }); 
    stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = solidRed }); 
    stylesPart.Stylesheet.CellStyleFormats = new CellStyleFormats(); 
    stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat { FillId = 0, ApplyFill = false }); 
    stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat { FillId = 1, ApplyFill = true }); 
    stylesPart.Stylesheet.CellFormats = new CellFormats(); 
    stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0 }); 
    stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 1 }); 
    stylesPart.Stylesheet.CellStyles = new CellStyles(); 
    stylesPart.Stylesheet.CellStyles.AppendChild(new CellStyle { Name = "None", FormatId = 0 }); 
    stylesPart.Stylesheet.CellStyles.AppendChild(new CellStyle { Name = "Solid Red", FormatId = 1 }); 

    stylesPart.Stylesheet.Save(); 

    Console.WriteLine("Creating sheet data"); 
    var sheetData = wsPart.Worksheet.AppendChild(new SheetData()); 

    Console.WriteLine("Adding rows/cells..."); 

    var row = sheetData.AppendChild(new Row()); 
    row.AppendChild(new Cell() { CellValue = new CellValue("This"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("is"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("a"),  DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("test."), DataType = CellValues.String }); 

    sheetData.AppendChild(new Row()); 

    row = sheetData.AppendChild(new Row()); 
    row.AppendChild(new Cell() { CellValue = new CellValue("Value:"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("123"),  DataType = CellValues.Number }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("Formula:"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellFormula = new CellFormula("B3"), StyleIndex = 1 }); // 

    Console.WriteLine("Saving worksheet"); 
    wsPart.Worksheet.Save(); 

    Console.WriteLine("Creating sheet list"); 
    var sheets = spreadsheet.WorkbookPart.Workbook.AppendChild(new Sheets()); 
    sheets.AppendChild(new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(wsPart), SheetId = 1, Name = "Test" }); 

    Console.WriteLine("Saving workbook"); 
    spreadsheet.WorkbookPart.Workbook.Save(); 

    Console.WriteLine("Done."); 
} 

Hier ist die erzeugte XML:

workbook.xml

<?xml version="1.0" encoding="utf-8"?> 
<x:workbook xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 
    <x:sheets> 
    <x:sheet name="Test" sheetId="1" r:id="Rbad86b8c80844a16" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" /> 
    </x:sheets> 
</x:workbook> 

styles.xml

Arbeitsblatt/sheet.xml

<?xml version="1.0" encoding="utf-8"?> 
<x:worksheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> 
    <x:sheetData> 
    <x:row> 
     <x:c t="str"><x:v>This</x:v></x:c> 
     <x:c t="str"><x:v>is</x:v></x:c> 
     <x:c t="str"><x:v>a</x:v></x:c> 
     <x:c t="str"><x:v>test.</x:v></x:c> 
    </x:row> 
    <x:row /> 
    <x:row> 
     <x:c t="str"><x:v>Value:</x:v></x:c> 
     <x:c t="n"><x:v>123</x:v></x:c> 
     <x:c t="str"><x:v>Formula:</x:v></x:c> 
     <x:c s="1"><x:f>B3</x:f></x:c> 
    </x:row> 
    </x:sheetData> 
</x:worksheet> 

Die letzte Zelle der letzten Zeile ist, wo ich versuche, den Stil hinzuzufügen.

Dies alles richtig überprüft, wenn ich es durch das OpenXML SDK Productivity Tool ausführen, aber, wenn ich die Datei in Excel zu öffnen versuchen, ich die folgende Fehlermeldung erhalten:

Repaired Records: Format from /xl/styles.xml part (Styles)

Die Tabelle zeigt dann aber Die Füllung wird nicht angewendet.

Irgendeine Idee, wie man das beheben kann?

+1

@Am_I_Helpful Ein .xslx nur eine Zip-Datei ist. Die XML-Inhalte sind innen. – Polynomial

+0

War mir dessen nicht bewusst. Danke, es hat geholfen! Und, +1. –

Antwort

73

Richtig, ich habe es nach vielen Experimenten herausgefunden.

Es stellt sich heraus, dass Excel reserviert Stile 0 und 1 für normale Zellen und "Gray125" Muster füllen jeweils. Der Großteil des obigen Codes kann entfernt werden, da wir nur einen CellFormat wirklich brauchen.

Arbeitscode:

Console.WriteLine("Creating document"); 
using (var spreadsheet = SpreadsheetDocument.Create("output.xlsx", SpreadsheetDocumentType.Workbook)) 
{ 
    Console.WriteLine("Creating workbook"); 
    spreadsheet.AddWorkbookPart(); 
    spreadsheet.WorkbookPart.Workbook = new Workbook(); 
    Console.WriteLine("Creating worksheet"); 
    var wsPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>(); 
    wsPart.Worksheet = new Worksheet(); 

    var stylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>(); 
    stylesPart.Stylesheet = new Stylesheet(); 

    Console.WriteLine("Creating styles"); 

    // blank font list 
    stylesPart.Stylesheet.Fonts = new Fonts(); 
    stylesPart.Stylesheet.Fonts.Count = 1; 
    stylesPart.Stylesheet.Fonts.AppendChild(new Font()); 

    // create fills 
    stylesPart.Stylesheet.Fills = new Fills(); 

    // create a solid red fill 
    var solidRed = new PatternFill() { PatternType = PatternValues.Solid }; 
    solidRed.ForegroundColor = new ForegroundColor { Rgb = HexBinaryValue.FromString("FFFF0000") }; // red fill 
    solidRed.BackgroundColor = new BackgroundColor { Indexed = 64 }; 

    stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.None } }); // required, reserved by Excel 
    stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = new PatternFill { PatternType = PatternValues.Gray125 } }); // required, reserved by Excel 
    stylesPart.Stylesheet.Fills.AppendChild(new Fill { PatternFill = solidRed }); 
    stylesPart.Stylesheet.Fills.Count = 3; 

    // blank border list 
    stylesPart.Stylesheet.Borders = new Borders(); 
    stylesPart.Stylesheet.Borders.Count = 1; 
    stylesPart.Stylesheet.Borders.AppendChild(new Border()); 

    // blank cell format list 
    stylesPart.Stylesheet.CellStyleFormats = new CellStyleFormats(); 
    stylesPart.Stylesheet.CellStyleFormats.Count = 1; 
    stylesPart.Stylesheet.CellStyleFormats.AppendChild(new CellFormat()); 

    // cell format list 
    stylesPart.Stylesheet.CellFormats = new CellFormats(); 
    // empty one for index 0, seems to be required 
    stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat()); 
    // cell format references style format 0, font 0, border 0, fill 2 and applies the fill 
    stylesPart.Stylesheet.CellFormats.AppendChild(new CellFormat { FormatId = 0, FontId = 0, BorderId = 0, FillId = 2, ApplyFill = true }).AppendChild(new Alignment { Horizontal = HorizontalAlignmentValues.Center }); 
    stylesPart.Stylesheet.CellFormats.Count = 2; 

    stylesPart.Stylesheet.Save(); 

    Console.WriteLine("Creating sheet data"); 
    var sheetData = wsPart.Worksheet.AppendChild(new SheetData()); 

    Console.WriteLine("Adding rows/cells..."); 

    var row = sheetData.AppendChild(new Row()); 
    row.AppendChild(new Cell() { CellValue = new CellValue("This"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("is"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("a"),  DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("test."), DataType = CellValues.String }); 

    sheetData.AppendChild(new Row()); 

    row = sheetData.AppendChild(new Row()); 
    row.AppendChild(new Cell() { CellValue = new CellValue("Value:"), DataType = CellValues.String }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("123"),  DataType = CellValues.Number }); 
    row.AppendChild(new Cell() { CellValue = new CellValue("Formula:"), DataType = CellValues.String }); 
    // style index = 1, i.e. point at our fill format 
    row.AppendChild(new Cell() { CellFormula = new CellFormula("B3"), DataType = CellValues.Number, StyleIndex = 1 }); 

    Console.WriteLine("Saving worksheet"); 
    wsPart.Worksheet.Save(); 

    Console.WriteLine("Creating sheet list"); 
    var sheets = spreadsheet.WorkbookPart.Workbook.AppendChild(new Sheets()); 
    sheets.AppendChild(new Sheet() { Id = spreadsheet.WorkbookPart.GetIdOfPart(wsPart), SheetId = 1, Name = "Test" }); 

    Console.WriteLine("Saving workbook"); 
    spreadsheet.WorkbookPart.Workbook.Save(); 

    Console.WriteLine("Done."); 
} 

Einige Ratschläge:

Verwenden ClosedXML, wenn Sie diesen Wahnsinn vermeiden wollen.

Ich kann ClosedXML nicht genug empfehlen, wenn Sie diese Art von Arbeit machen. Das OpenXML-API und -Format ist fürchterlich langwierig, um alleine mit allen möglichen undokumentierten Fällen zu arbeiten. ClosedXML tut so viel von dem Bein für Sie. Sie sind auch sehr gut darin, Fehler schnell zu beheben.

+23

Übrigens, wenn jemand zu einem späteren Zeitpunkt darauf zurückkommt, empfehle ich sehr, die ClosedXML-Bibliothek zu überprüfen. Es ist so viel einfacher zu arbeiten als direkt mit OpenXML. – Polynomial

+7

Ich würde dir mehr als nur +1 geben, wenn ich auf ClosedXML zeigen könnte. Das ist eine sehr einfach zu bedienende Bibliothek ... Danke! – pennyrave

+0

Wie kann ich diesen Code so ändern, dass eine Änderung an einer vorhandenen Tabelle vorgenommen wird? –

2

Eine generische Antwort, all das habe ich nach dem Test gefunden, also keine Dokumentation zu zeigen.

Sobald Sie eine CellFormats Sammlung im Stylesheet festgelegt läuft Excel eine tiefere Validierung darauf.

CellFormats kann nicht leer sein, es muss mindestens eine CellFormat da sein.

Sobald Sie eine CellFormat hinzufügen, wird Excel beschweren, wenn Fills, Fonts oder Borders Sammlungen leer sind.

Erste Font wird als Standard für die gesamte Arbeitsmappe und auch Spalte/Zeile Header in Excel verwendet.

wird Excel ersten CellFormat ignorieren, so dass nur eine leere hinzuzufügen.

Wenn Sie ein Border oder Fill in Ihrem Format benötigen, Excel auch ignoriert erste Border und Fill, so auch leere als erstes Kind in Borders und Fills hinzuzufügen.

Schließlich, beginnend in der zweiten CellFormat (s = "1") Sie sind gut zu gehen.

in Excel 2010.

Geprüft