You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用DocumentFormat.OpenXml编辑Excel模板时添加新样式且不覆盖原有样式的方法

DocumentFormat.OpenXml编辑Excel模板时添加新样式且不覆盖原有样式的方法

我太懂你踩的这个坑了——直接给stylesPart.Stylesheet赋值新对象,等于把模板里原有的所有样式(包括字体、填充、边框、单元格格式)全清空了,这就是为什么换个模板就失效的原因。咱们要做的是在原有样式的基础上追加新格式,而不是推倒重建整个样式表。

核心修改思路

不要新建Stylesheet,而是复用模板原有的样式表节点,只追加我们需要的新格式(比如日期、欧元格式),同时保证所有节点的计数属性和实际元素数量匹配,避免Excel报错。

具体代码修改

1. 复用原有StyleSheet,不要新建

先把模板原有的样式表取出来,所有操作都基于它:

var stylesPart = workbook.WorkbookPart.WorkbookStylesPart;
var stylesheet = stylesPart.Stylesheet; // 取模板自带的样式表,不是new!

2. 追加自定义数字格式(欧元),不覆盖原有格式

自定义格式的ID要从164开始(0-163是Excel内置格式),还要避免重复添加:

// 处理自定义欧元数字格式
var numberingFormats = stylesheet.NumberingFormats ?? new NumberingFormats();

// 检查模板是否已存在该格式,避免重复追加
if (!numberingFormats.Elements<NumberingFormat>().Any(nf => nf.NumberFormatId == 164))
{
    numberingFormats.AppendChild(new NumberingFormat
    {
        NumberFormatId = 164,
        FormatCode = "#,##0\\ \"€\""
    });
}

// 如果模板原来没有NumberingFormats节点,把它加到样式表里
if (stylesheet.NumberingFormats == null)
{
    stylesheet.AppendChild(numberingFormats);
}

// 必须更新Count属性,否则Excel打开会提示文件损坏
numberingFormats.Count = (uint)numberingFormats.Elements<NumberingFormat>().Count();

3. 在原有CellFormats基础上追加新的单元格格式

新格式要追加在模板原有格式的后面,用originalCellFormatCount记录原有数量,方便计算新格式的索引:

var cellFormats = stylesheet.CellFormats;
int originalCellFormatCount = (int)cellFormats.Count.Value; // 记录原有格式数量

// 追加1:短日期格式(用Excel内置ID 14)
cellFormats.AppendChild(new CellFormat
{
    NumberFormatId = 14,
    ApplyNumberFormat = true,
    FormatId = 0 // 复用模板默认的基础样式(字体、填充、边框)
});

// 追加2:欧元格式(用我们刚加的自定义ID 164)
cellFormats.AppendChild(new CellFormat
{
    NumberFormatId = 164,
    ApplyNumberFormat = true,
    FormatId = 0
});

// 追加3:带时间的日期格式(内置ID 22)
cellFormats.AppendChild(new CellFormat
{
    NumberFormatId = 22,
    ApplyNumberFormat = true,
    FormatId = 0
});

// 更新CellFormats的Count属性,这步是关键!
cellFormats.Count = (uint)cellFormats.Elements<CellFormat>().Count();

4. 调整StyleIndex取值,对应新追加的格式

因为新格式是追加在原有格式后面的,所以要用之前记录的originalCellFormatCount计算索引,不要硬编码:

// 提前计算好新样式的索引,避免硬编码出错
uint shortDateStyleIndex = (uint)originalCellFormatCount;
uint euroStyleIndex = (uint)originalCellFormatCount + 1;
uint dateTimeStyleIndex = (uint)originalCellFormatCount + 2;

// 后面给单元格设置样式时用这些变量
if (t == CellValues.Date)
    cell.StyleIndex = (dtwt ?? false) ? dateTimeStyleIndex : shortDateStyleIndex;

if (mt != null)
    cell.StyleIndex = (mt ?? 0) == 164 ? euroStyleIndex : 0; // 0是模板原有的默认样式

必须注意的细节

  1. 更新Count属性:NumberingFormats、CellFormats这些节点的Count属性必须和实际元素数量一致,否则Excel打开文件会提示损坏。
  2. 自定义格式ID唯一:自定义NumberingFormatId必须从164开始,且不要和模板里已有的自定义ID重复(可以遍历原有NumberingFormats找最大ID再加1)。
  3. 复用基础样式:我们的新格式用FormatId = 0,对应模板原有的默认单元格样式,这样就不用重新定义字体、填充、边框,不会破坏模板原有样式。

把你原有的那段重建Stylesheet的代码,换成上面的复用式代码,再调整StyleIndex的取值,两个端点的模板原有样式就都能保留,同时新的日期、欧元格式也能正常应用了!

火山引擎 最新活动