OpenXML 动态创建“表/数据透视表”

Lea*_*res 5 .net c# excel openxml openxml-sdk

我正在创建一个在内存上生成 Excel 的示例程序。\n该程序已经生成了 Excel,但是我无法让该表工作...

\n\n

程序:

\n\n
public class Program\n{\n    static void Main(string[] args)\n    {\n        CreateCurrentAccount();\n    }\n\n    static void CreateCurrentAccount()\n    {\n        byte[] _buffer = ExcelGenerator.CurrentAccount.GetExcel();\n        File.WriteAllBytes("CurrentAccount.xlsx", _buffer);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

Excel生成器类:

\n\n
public class ExcelGenerator\n{\n    static uint? _generalStyle = 0;\n    static uint? _dateStyle = 1;\n    static uint? _currencyStyle = 2;\n    static uint? _percentageStyle = 3;\n    static int maxStyleSheetName = 31;\n\n    public static class CurrentAccount\n    {\n        static uint? _headerStyle = 4;\n        static uint? _tableHeaderStyle = 5;\n        static uint? _totalHeaderStyle = 6;\n\n        public static byte[] GetExcel()\n        {\n            using (MemoryStream ms = new MemoryStream())\n            {\n                SpreadsheetDocument spreadsheet;\n                Worksheet worksheet;\n\n                spreadsheet = OpenXML.CreateWorkbook(ms);\n\n                // styles\n                OpenXML.AddBasicStyles(spreadsheet);\n                AddAdvancedStyles(spreadsheet);\n\n                string styleSheetName = ("Conta Corrente" /* + customer.Name*/);\n                OpenXML.AddWorksheet(spreadsheet, styleSheetName.Length > maxStyleSheetName ? styleSheetName.Substring(0, maxStyleSheetName) : styleSheetName);\n                worksheet = spreadsheet.WorkbookPart.WorksheetParts.First().Worksheet;\n\n                // Sheet 1 Header\n                OpenXML.MergeTwoCells(worksheet, "A1", "F1");\n                OpenXML.SetCellValue(spreadsheet, worksheet, 1, 1, CellValues.String, "Conta Corrente", _headerStyle, true);\n\n                // Header Table\n                OpenXML.SetCellValue(spreadsheet, worksheet, 1, 3, CellValues.String, "Tipo de Doc.", _tableHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 2, 3, CellValues.String, "Nr. Doc.", _tableHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 3, 3, CellValues.String, "Valor Doc.", _tableHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 4, 3, CellValues.String, "Valor Pendente", _tableHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 5, 3, CellValues.String, "Data Registo", _tableHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 6, 3, CellValues.String, "Data Vencimento", _tableHeaderStyle, true);\n\n                // Table\n                var currentAccountData = GetData();\n\n                uint rowIdx = 4;\n                foreach (var item in currentAccountData)\n                {\n                    OpenXML.SetCellValue(spreadsheet, worksheet, 1, rowIdx, CellValues.String, item.TypeDoc, _generalStyle, true);\n                    OpenXML.SetCellValue(spreadsheet, worksheet, 2, rowIdx, CellValues.String, item.NrDoc, _generalStyle, true);\n                    if (item.DocValue != null)\n                        OpenXML.SetCellValue(spreadsheet, worksheet, 3, rowIdx, Convert.ToDouble(item.DocValue), _currencyStyle, true);\n                    if (item.PendingValue != null)\n                        OpenXML.SetCellValue(spreadsheet, worksheet, 4, rowIdx, Convert.ToDouble(item.PendingValue), _currencyStyle, true);\n                    if (item.RecordDate != null)\n                        OpenXML.SetCellValue(spreadsheet, worksheet, 5, rowIdx, item.RecordDate, _dateStyle, true);\n                    if (item.SalaryDate != null)\n                        OpenXML.SetCellValue(spreadsheet, worksheet, 6, rowIdx, item.SalaryDate, _dateStyle, true);\n\n                    rowIdx++;\n                }\n\n                TableParts tableParts1 = new TableParts() { Count = (uint)1U };\n                TablePart tablePart1 = new TablePart() { Id = "rId1" };\n                tableParts1.Append(tablePart1);\n                worksheet.Append(tableParts1);\n\n                OpenXML.CreateTable(spreadsheet, worksheet, "table1", 3U, 1U, (uint)currentAccountData.Count + 3, 6U);\n                TableDefinitionPart tableDefinitionPart1 = worksheet.WorksheetPart.TableDefinitionParts.FirstOrDefault<TableDefinitionPart>();\n\n                // Total\n                OpenXML.SetCellValue(spreadsheet, worksheet, 8, 2, CellValues.String, "Total Documento", _totalHeaderStyle, true);\n                OpenXML.SetCellFormula(spreadsheet, worksheet, 9, 2, "=SUM(C4:C1048576)", 2, true);\n\n                OpenXML.SetCellValue(spreadsheet, worksheet, 8, 3, CellValues.String, "Total Pendente", _totalHeaderStyle, true);\n                OpenXML.SetCellFormula(spreadsheet, worksheet, 9, 3, "=SUM(D4:D1048576)", 2, true);\n\n                // Last Sync\n                var lastSync = DateTime.Now;\n                OpenXML.SetCellValue(spreadsheet, worksheet, 8, 1, CellValues.String, "\xc3\x9altima Sincroniza\xc3\xa7\xc3\xa3o", _totalHeaderStyle, true);\n                OpenXML.SetCellValue(spreadsheet, worksheet, 9, 1, lastSync, _dateStyle, true);\n\n                // Set column widths\n                OpenXML.SetColumnWidth(worksheet, 1, 22);\n                OpenXML.SetColumnWidth(worksheet, 2, 22);\n                OpenXML.SetColumnWidth(worksheet, 3, 22);\n                OpenXML.SetColumnWidth(worksheet, 4, 22);\n                OpenXML.SetColumnWidth(worksheet, 5, 22);\n                OpenXML.SetColumnWidth(worksheet, 6, 22);\n\n                OpenXML.SetColumnWidth(worksheet, 8, 22);\n                OpenXML.SetColumnWidth(worksheet, 9, 22);\n\n                worksheet.Save();\n                spreadsheet.Close();\n\n                return ms.ToArray();\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

创建表方法

\n\n
public static void CreateTable(SpreadsheetDocument document, Worksheet worksheet, string TableName, uint rowStart, uint columnStart, uint rowEnd, uint columnEnd)\n    {\n        string cellAddressStart = ColumnNameFromIndex(columnStart) + rowStart;\n        string cellAddressEnd = ColumnNameFromIndex(columnEnd) + rowEnd;\n        string tableAddress = cellAddressStart + ":" + cellAddressEnd;\n\n        TableDefinitionPart tableDefinitionPart1 = worksheet.WorksheetPart.AddNewPart<TableDefinitionPart>("rId1");\n\n        Table table1 = new Table() { Id = (UInt32Value)2U, Name = TableName, DisplayName = TableName, Reference = tableAddress, TotalsRowShown = false };\n        AutoFilter autoFilter1 = new AutoFilter() { Reference = tableAddress };\n\n        uint cellRangeCount = columnEnd - columnStart;\n        TableColumns tableColumns1 = new TableColumns() { Count = (UInt32Value)(cellRangeCount) };\n        uint cellCount = 1;\n        for (uint idxColumns = columnStart; idxColumns < columnEnd; idxColumns++)\n        {\n            CellValue cell = GetCellValue(document, worksheet, idxColumns, rowStart);\n            TableColumn tableColumn1 = new TableColumn() { Id = (UInt32Value)cellCount, Name = cell.InnerText };\n            tableColumns1.Append(tableColumn1);\n            cellCount++;\n        }\n\n        TableStyleInfo tableStyleInfo1 = new TableStyleInfo() { Name = "TableStyleMedium2", \n                                                                ShowFirstColumn = false, \n                                                                ShowLastColumn = false, \n                                                                ShowRowStripes = true, \n                                                                ShowColumnStripes = false };\n\n        table1.Append(autoFilter1);\n        table1.Append(tableColumns1);\n        table1.Append(tableStyleInfo1);\n\n        tableDefinitionPart1.Table = table1;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

我正在添加单元格(行)

\n\n
var currentAccountData = GetData();\n\nuint rowIdx = 4;\nforeach (var item in currentAccountData)\n{\n    OpenXML.SetCellValue(spreadsheet, worksheet, 1, rowIdx, CellValues.String, item.TypeDoc, _generalStyle, true);\n    OpenXML.SetCellValue(spreadsheet, worksheet, 2, rowIdx, CellValues.String, item.NrDoc, _generalStyle, true);\n    if (item.DocValue != null)\n        OpenXML.SetCellValue(spreadsheet, worksheet, 3, rowIdx, Convert.ToDouble(item.DocValue), _currencyStyle, true);\n    if (item.PendingValue != null)\n        OpenXML.SetCellValue(spreadsheet, worksheet, 4, rowIdx, Convert.ToDouble(item.PendingValue), _currencyStyle, true);\n    if (item.RecordDate != null)\n        OpenXML.SetCellValue(spreadsheet, worksheet, 5, rowIdx, item.RecordDate, _dateStyle, true);\n    if (item.SalaryDate != null)\n        OpenXML.SetCellValue(spreadsheet, worksheet, 6, rowIdx, item.SalaryDate, _dateStyle, true);\n\n    rowIdx++;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后创建表格部分

\n\n
TableParts tableParts1 = new TableParts() { Count = (uint)1U };\nTablePart tablePart1 = new TablePart() { Id = "rId1" };\ntableParts1.Append(tablePart1);\nworksheet.Append(tableParts1);\n
Run Code Online (Sandbox Code Playgroud)\n\n

之后,我使用方法 OpenXML.CreateTable

\n\n
OpenXML.CreateTable(spreadsheet, worksheet, "table1", 3U, 1U, (uint)currentAccountData.Count + 3, 6U);\n
Run Code Online (Sandbox Code Playgroud)\n\n

我究竟做错了什么?

\n\n

如果您需要更多代码,我将上传该应用程序。\n谢谢。

\n\n

编辑:

\n\n

当我打开Excel时,它说:

\n\n
\n

删除的部分:/xl/tables/table.xml 部分包含 XML 错误。(表)\n 文档必须恰好包含一个根元素。第 1 行,第 0 列。

\n
\n

Isa*_*pov -1

我究竟做错了什么?

你的调试方法对我来说似乎是错误的。我建议采用以下方法之一:

  • A。将生成的 xml 与手工制作的 xlsx 文件进行比较。
  • b. 从 OpenXML 生产力工具生成的代码开始(因此它会在您的应用程序中生成静态表),然后逐步修改/重构它以使用应用程序中的动态数据并匹配您的编码标准 - 这样您就可以发现错误迭代之一或只是获得一个干净的工作解决方案