Стили ячеек в электронной таблице OpenXML (SpreadsheetML)
я производил .таблица xlsx в C# с помощью OpenXML SDK, но не может понять, как заставить стили ячеек работать. Я изучал файлы, созданные Excel, и не могу понять, как это делается.
прямо сейчас я создаю заливку, создаю CellStyleFormat
это указывает на заливку, создавая CellFormat
это указывает на индекс CellStyleFormat
, затем создать CellStyle
к CellFormat
.
вот код, который я использую для создания документ:
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.");
}
вот сгенерированный XML:
книги.в 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>
стили.в XML
<?xml version="1.0" encoding="utf-8"?>
<x:styleSheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:fills>
<x:fill>
<x:patternFill patternType="none" />
</x:fill>
<x:fill>
<x:patternFill patternType="solid">
<x:bgColor rgb="FF00FF00" />
</x:patternFill>
</x:fill>
</x:fills>
<x:cellStyleXfs>
<x:xf fillId="0" applyFill="0" />
<x:xf fillId="1" applyFill="1" />
</x:cellStyleXfs>
<x:cellXfs>
<x:xf xfId="0" />
<x:xf xfId="1" />
</x:cellXfs>
<x:cellStyles>
<x:cellStyle name="None" xfId="0" />
<x:cellStyle name="Solid Red" xfId="1" />
</x:cellStyles>
</x:styleSheet>
листы/лист.в 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>
в последней ячейке последней строки я пытаюсь добавить стиль.
все это правильно проверяется, когда я запускаю его через OpenXML SDK Productivity Tool, но, когда я пытаюсь открыть файл в Excel, я получаю следующая ошибка:
восстановленные записи: формат из /xl / styles.xml часть (стили)
затем отображается электронная таблица, но заливка не применяется.
есть идеи, как это исправить?
2 ответов
правильно, мне удалось выяснить это, после многих экспериментов.
получается, что Excel резервов стили 0 и 1 для нормальных клеток и "Gray125" образец заполнения соответственно. Большая часть вышеуказанного кода может быть удалена, так как нам нужно только CellFormat
действительно.
рабочий код:
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.");
}
несколько советов:
используйте ClosedXML, если вы хотите избежать этого безумия.
я не могу рекомендовать ClosedXML достаточно высоко, если вы делаете такую работу. API и формат OpenXML ужасно утомительны для работы самостоятельно, со всеми видами недокументированных случаев. ClosedXML делает так много работы ноги для вас. Они также очень хороши в исправлении ошибок быстро.
более общий ответ, все это я нашел после тестирования, поэтому нет документации, на которую можно указать.
после установки CellFormats
коллекция в таблице стилей Excel выполняет более глубокую проверку на нем.
CellFormats
не может быть пустым, он должен быть хотя бы один CellFormat
там.
после добавления CellFormat
, в Excel будет жаловаться, если Fills
, Fonts
или Borders
коллекции пусты.
первый Font
используется по умолчанию для всей книги, а также Заголовки столбцов/строк в Excel.
Excel будет игнорировать первый CellFormat
, поэтому просто добавьте пустой.
Если вам нужен Border
или Fill
в вашем формате Excel также будет игнорировать first Border
и Fill
, поэтому также добавьте пустые в качестве первого ребенка в Borders
и Fills
.
наконец, начиная со второй CellFormat
(s = "1"
) вы хорошо идти.
протестировано в Excel 2010.