使用 C# 和 OpenXML 合并工作表时保留相同的 Excel 样式
Retain same Excel styles when merging sheets using C# and OpenXML
在 C# 中将多个 excel sheet 合并到一个 excel 文档时出现问题。所以本质上它是一个包含多个 sheet 的工作簿。然而这有效
问题是它没有保留格式和样式。第一个 sheet 的格式正确,但它在整个 sheet 中复制了相同的样式,而这是不应该的。
我需要帮助来合并 sheet 并保持相同的样式和格式。
循环 sheets C#
// For each worksheet in the child workbook...
foreach (Sheet childSheet in childWorkbookSheets)
{
// Get a worksheet part for the child worksheet using
// it's relationship Id.
childWorksheetPart = (WorksheetPart)childWorkbook.WorkbookPart.GetPartById(childSheet.Id);
// Add a worksheet part to the merged workbook based on
// the child worksheet.
mergedWorksheetPart = mergedWorkbookPart.AddPart<WorksheetPart>(childWorksheetPart);
//There should be only one worksheet that is set
//as the main view.
CleanView(mergedWorksheetPart);
// Create a Sheet element for the new sheet in the
// merged workbook.
newMergedSheet = new Sheet();
// Set the Name, Id, and SheetId attributes of the
// new Sheet element.
newMergedSheet.Name = GenerateWorksheetName(mergedWorkbookSheets, childSheet.Name.Value);
newMergedSheet.Id = mergedWorkbookPart.GetIdOfPart(mergedWorksheetPart);
newMergedSheet.SheetId = (uint)mergedWorkbookSheets.ChildElements.Count + 1;
// Add the new Sheet element to the Sheets element in the
// merged workbook.
mergedWorkbookSheets.Append(newMergedSheet);
// Get the SheetData element of the new worksheet part
// in the merged workbook.
mergedSheetData = mergedWorksheetPart.Worksheet.GetFirstChild<SheetData>();
if (styleCounter == 0)
{
mergedWorkbook.WorkbookPart.AddPart<WorkbookStylesPart>(childSharedStylePart);
}
styleCounter++;
// For each row of data...
foreach (Row row in mergedSheetData.Elements<Row>())
{
// For each cell in the row...
foreach (Cell cell in row.Elements<Cell>())
{
// If the cell is using a shared string, merge
// the string from the child workbook into the merged
// workbook.
CellFormat cellFormat = cell.StyleIndex != null ? GetCellFormat(mergedWorkbookPart, cell.StyleIndex).CloneNode(true) as CellFormat : new CellFormat();
GetCellFormat(mergedWorkbookPart, cell.StyleIndex);
if (cell.DataType != null &&
cell.DataType.Value == CellValues.SharedString)
{
ProcessCellSharedString(mergedWorksheetPart, cell, mergedSharedStringTablePart, childSharedStringTablePart);
}
cell.StyleIndex = InsertCellFormat(mergedWorkbookPart, cellFormat);
mergedSheetData.AppendChild(new Cell());
mergedCellformat = GetCellFormat(mergedWorkbookPart, cell.StyleIndex);
//cellFormat.ReplaceChild(mergedCellformat,mergedCellformat);
//attempt to add styling to the other worksheets
mergedCellformat.FillId.Value = (cellFormat.FillId.Value);
mergedCellformat.BorderId.Value = (cellFormat.BorderId.Value);
mergedCellformat.FontId.Value = (cellFormat.FontId.Value);
//mergedCellformat.FormatId = (cellFormat.FormatId.Value);
//cellFormat.AppendChild(mergedCellformat);
//cellFormat.Append(mergedCellformat);
}
}
第一个sheet是完美的,它保留了格式并且是正确的。
其余 sheet 的格式随处可见。不一样。
private static CellFormat GetCellFormat(WorkbookPart workbookPart, uint styleIndex)
{
return workbookPart.WorkbookStylesPart.Stylesheet.Elements<CellFormats>().First().Elements<CellFormat>().ElementAt((int)styleIndex);
}
private static uint InsertCellFormat(WorkbookPart workbookPart, CellFormat cellFormat)
{
CellFormats cellFormats = workbookPart.WorkbookStylesPart.Stylesheet.Elements<CellFormats>().First();
cellFormats.Append(cellFormat);
return (uint)cellFormats.Count++;
}
我不知道你是否可以这样做,但我会尝试从选择范围的角度来解决这个问题,并使用与 'PasteSpecial' 等效的 OPENXML,如下所述:
因此,与其尝试单独获取格式,不如创建单元格、填充数据然后复制格式...
定义一个源RangeSet。
https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.rangeset_members.aspx
那个的 CloneNode(true)。
然后将其插入合并的 sheet 中。 (因为这应该复制范围内的所有内容,包括样式)。
(免责声明:我没有时间对此进行测试,但希望该建议有助于找到替代途径)
我会考虑创建一个 Worksheet Template。
使用模板创建新的 sheet 涉及如下 (VBA) 代码:
'Insert sheet template
With ThisWorkbook
Set sh = Sheets.Add(Type:=Application.TemplatesPath & shName, _
after:=.Sheets(.Sheets.Count))
End With
然后用原始数据填充它(无论是通过 (VBA) .PasteSpecial Paste:=xlPasteValues
还是直接给单元格赋值)并命名它。
上述代码的 OpenXML 等价物应该很容易找到。
在 C# 中将多个 excel sheet 合并到一个 excel 文档时出现问题。所以本质上它是一个包含多个 sheet 的工作簿。然而这有效
问题是它没有保留格式和样式。第一个 sheet 的格式正确,但它在整个 sheet 中复制了相同的样式,而这是不应该的。
我需要帮助来合并 sheet 并保持相同的样式和格式。
循环 sheets C#
// For each worksheet in the child workbook...
foreach (Sheet childSheet in childWorkbookSheets)
{
// Get a worksheet part for the child worksheet using
// it's relationship Id.
childWorksheetPart = (WorksheetPart)childWorkbook.WorkbookPart.GetPartById(childSheet.Id);
// Add a worksheet part to the merged workbook based on
// the child worksheet.
mergedWorksheetPart = mergedWorkbookPart.AddPart<WorksheetPart>(childWorksheetPart);
//There should be only one worksheet that is set
//as the main view.
CleanView(mergedWorksheetPart);
// Create a Sheet element for the new sheet in the
// merged workbook.
newMergedSheet = new Sheet();
// Set the Name, Id, and SheetId attributes of the
// new Sheet element.
newMergedSheet.Name = GenerateWorksheetName(mergedWorkbookSheets, childSheet.Name.Value);
newMergedSheet.Id = mergedWorkbookPart.GetIdOfPart(mergedWorksheetPart);
newMergedSheet.SheetId = (uint)mergedWorkbookSheets.ChildElements.Count + 1;
// Add the new Sheet element to the Sheets element in the
// merged workbook.
mergedWorkbookSheets.Append(newMergedSheet);
// Get the SheetData element of the new worksheet part
// in the merged workbook.
mergedSheetData = mergedWorksheetPart.Worksheet.GetFirstChild<SheetData>();
if (styleCounter == 0)
{
mergedWorkbook.WorkbookPart.AddPart<WorkbookStylesPart>(childSharedStylePart);
}
styleCounter++;
// For each row of data...
foreach (Row row in mergedSheetData.Elements<Row>())
{
// For each cell in the row...
foreach (Cell cell in row.Elements<Cell>())
{
// If the cell is using a shared string, merge
// the string from the child workbook into the merged
// workbook.
CellFormat cellFormat = cell.StyleIndex != null ? GetCellFormat(mergedWorkbookPart, cell.StyleIndex).CloneNode(true) as CellFormat : new CellFormat();
GetCellFormat(mergedWorkbookPart, cell.StyleIndex);
if (cell.DataType != null &&
cell.DataType.Value == CellValues.SharedString)
{
ProcessCellSharedString(mergedWorksheetPart, cell, mergedSharedStringTablePart, childSharedStringTablePart);
}
cell.StyleIndex = InsertCellFormat(mergedWorkbookPart, cellFormat);
mergedSheetData.AppendChild(new Cell());
mergedCellformat = GetCellFormat(mergedWorkbookPart, cell.StyleIndex);
//cellFormat.ReplaceChild(mergedCellformat,mergedCellformat);
//attempt to add styling to the other worksheets
mergedCellformat.FillId.Value = (cellFormat.FillId.Value);
mergedCellformat.BorderId.Value = (cellFormat.BorderId.Value);
mergedCellformat.FontId.Value = (cellFormat.FontId.Value);
//mergedCellformat.FormatId = (cellFormat.FormatId.Value);
//cellFormat.AppendChild(mergedCellformat);
//cellFormat.Append(mergedCellformat);
}
}
第一个sheet是完美的,它保留了格式并且是正确的。 其余 sheet 的格式随处可见。不一样。
private static CellFormat GetCellFormat(WorkbookPart workbookPart, uint styleIndex)
{
return workbookPart.WorkbookStylesPart.Stylesheet.Elements<CellFormats>().First().Elements<CellFormat>().ElementAt((int)styleIndex);
}
private static uint InsertCellFormat(WorkbookPart workbookPart, CellFormat cellFormat)
{
CellFormats cellFormats = workbookPart.WorkbookStylesPart.Stylesheet.Elements<CellFormats>().First();
cellFormats.Append(cellFormat);
return (uint)cellFormats.Count++;
}
我不知道你是否可以这样做,但我会尝试从选择范围的角度来解决这个问题,并使用与 'PasteSpecial' 等效的 OPENXML,如下所述:
因此,与其尝试单独获取格式,不如创建单元格、填充数据然后复制格式...
定义一个源RangeSet。 https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.rangeset_members.aspx
那个的 CloneNode(true)。 然后将其插入合并的 sheet 中。 (因为这应该复制范围内的所有内容,包括样式)。
(免责声明:我没有时间对此进行测试,但希望该建议有助于找到替代途径)
我会考虑创建一个 Worksheet Template。
使用模板创建新的 sheet 涉及如下 (VBA) 代码:
'Insert sheet template
With ThisWorkbook
Set sh = Sheets.Add(Type:=Application.TemplatesPath & shName, _
after:=.Sheets(.Sheets.Count))
End With
然后用原始数据填充它(无论是通过 (VBA) .PasteSpecial Paste:=xlPasteValues
还是直接给单元格赋值)并命名它。
上述代码的 OpenXML 等价物应该很容易找到。