You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让C#生成的自定义Excel匹配SharePoint导出Excel的外观

刚好之前做过类似的需求——用CSOM导出SharePoint列表数据到Excel,要完全复刻原生导出的样式,尤其是那个交替行底纹。折腾了一阵终于搞定了,下面是我验证过的方案,能完美适配任意行数,用OpenXML来实现(毕竟CSOM结合OpenXML是自定义Excel导出的常规操作):

实现思路

SharePoint原生导出的Excel有几个核心样式特点:

  • 表头:深蓝色底(RGB #4472C4)、白色加粗字体、细边框
  • 数据行:交替行底纹(奇数行白色,偶数行浅灰色 #F5F5F5)、黑色常规字体、细边框

为了适配任意行数,不要逐行设置样式,而是用OpenXML的条件格式功能,通过公式自动识别奇偶行并应用对应样式,这样不管数据有10行还是1000行,都能自动生效。

具体代码实现

首先需要引用DocumentFormat.OpenXml和DocumentFormat.OpenXml.Spreadsheet命名空间,然后分三部分实现:样式表定义、交替行条件格式添加、整合到CSOM导出流程。

1. 定义匹配原生样式的样式表

private static Stylesheet CreateSharePointLikeStylesheet()
{
    var stylesheet = new Stylesheet();

    // 字体集合:数据行黑字,表头白字加粗
    var fonts = new Fonts();
    // 数据行字体(默认黑字11号)
    fonts.Append(new Font(
        new Color { Rgb = HexBinaryValue.FromString("000000") },
        new FontSize { Val = 11 }));
    // 表头字体(白字11号加粗)
    fonts.Append(new Font(
        new Color { Rgb = HexBinaryValue.FromString("FFFFFF") },
        new FontSize { Val = 11 },
        new Bold()));

    // 填充集合:默认白色、表头蓝色、交替行浅灰
    var fills = new Fills();
    // 默认空填充
    fills.Append(new Fill(new PatternFill { PatternType = PatternValues.None }));
    // 125%灰度填充(OpenXML默认需要)
    fills.Append(new Fill(new PatternFill { PatternType = PatternValues.Gray125 }));
    // 表头填充(SharePoint原生蓝色)
    fills.Append(new Fill(new PatternFill
    {
        PatternType = PatternValues.Solid,
        ForegroundColor = new ForegroundColor { Rgb = HexBinaryValue.FromString("4472C4") },
        BackgroundColor = new BackgroundColor { Indexed = 64 }
    }));
    // 交替行浅灰填充
    fills.Append(new Fill(new PatternFill
    {
        PatternType = PatternValues.Solid,
        ForegroundColor = new ForegroundColor { Rgb = HexBinaryValue.FromString("F5F5F5") },
        BackgroundColor = new BackgroundColor { Indexed = 64 }
    }));

    // 边框集合:细边框(和原生导出一致)
    var borders = new Borders();
    var thinBorder = new Border(
        new LeftBorder { Style = BorderStyleValues.Thin },
        new RightBorder { Style = BorderStyleValues.Thin },
        new TopBorder { Style = BorderStyleValues.Thin },
        new BottomBorder { Style = BorderStyleValues.Thin },
        new DiagonalBorder());
    borders.Append(new Border()); // 默认无边框
    borders.Append(thinBorder); // 数据/表头单元格边框

    // 单元格格式集合:绑定字体、填充、边框
    var cellFormats = new CellFormats();
    // 默认格式
    cellFormats.Append(new CellFormat { FontId = 0, FillId = 0, BorderId = 0 });
    // 表头单元格格式
    cellFormats.Append(new CellFormat 
    { 
        FontId = 1, FillId = 2, BorderId = 1, 
        ApplyFont = true, ApplyFill = true, ApplyBorder = true 
    });
    // 数据行奇数行格式(白色背景)
    cellFormats.Append(new CellFormat 
    { 
        FontId = 0, FillId = 0, BorderId = 1, 
        ApplyFont = true, ApplyFill = true, ApplyBorder = true 
    });
    // 数据行偶数行格式(浅灰背景)
    cellFormats.Append(new CellFormat 
    { 
        FontId = 0, FillId = 3, BorderId = 1, 
        ApplyFont = true, ApplyFill = true, ApplyBorder = true 
    });

    // 把所有样式部分添加到样式表
    stylesheet.Append(fonts);
    stylesheet.Append(fills);
    stylesheet.Append(borders);
    stylesheet.Append(cellFormats);

    return stylesheet;
}

2. 添加交替行条件格式(适配任意行数)

private static void AddAlternatingRowConditionalFormatting(Worksheet worksheet, uint dataStartRow, uint dataEndRow, uint columnCount)
{
    var conditionalFormatting = new ConditionalFormatting();
    // 设置格式应用范围:从数据起始行到结束行,覆盖所有列
    var rangeRef = new SqRef($"{GetExcelColumnName(1)}{dataStartRow}:{GetExcelColumnName((int)columnCount)}{dataEndRow}");
    conditionalFormatting.Append(rangeRef);

    // 偶数行规则:公式判断行号为偶数,应用浅灰样式
    var evenRowRule = new CfRule
    {
        Type = CfRuleType.Formula,
        FormatId = 3, // 对应上面定义的偶数行格式ID
        Priority = 1
    };
    evenRowRule.Append(new Formula("MOD(ROW(),2)=0"));
    conditionalFormatting.Append(evenRowRule);

    // 奇数行规则:公式判断行号为奇数,应用白色样式
    var oddRowRule = new CfRule
    {
        Type = CfRuleType.Formula,
        FormatId = 2, // 对应奇数行格式ID
        Priority = 2
    };
    oddRowRule.Append(new Formula("MOD(ROW(),2)=1"));
    conditionalFormatting.Append(oddRowRule);

    // 把条件格式添加到工作表
    worksheet.Append(conditionalFormatting);
}

// 辅助方法:将列索引转换为Excel列名(比如1→A,27→AA)
private static string GetExcelColumnName(int columnIndex)
{
    string columnName = "";
    while (columnIndex > 0)
    {
        int remainder = (columnIndex - 1) % 26;
        columnName = Convert.ToChar('A' + remainder) + columnName;
        columnIndex = (columnIndex - 1) / 26;
    }
    return columnName;
}

3. 整合到CSOM导出流程

当你用CSOM获取到SharePoint列表数据后,按以下步骤整合样式:

// 1. 创建Excel文档(示例用OpenXML的SpreadsheetDocument)
using (var document = SpreadsheetDocument.Create("ExportedListData.xlsx", SpreadsheetDocumentType.Workbook))
{
    var workbookPart = document.AddWorkbookPart();
    workbookPart.Workbook = new Workbook();

    var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
    worksheetPart.Worksheet = new Worksheet(new SheetData());

    var sheets = workbookPart.Workbook.AppendChild(new Sheets());
    sheets.Append(new Sheet { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "List Data" });

    // 2. 添加样式表到文档
    var stylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
    stylesPart.Stylesheet = CreateSharePointLikeStylesheet();
    stylesPart.Stylesheet.Save();

    var sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();

    // 3. 写入表头(第1行,应用表头样式)
    var headerRow = new Row { RowIndex = 1 };
    foreach (var columnName in listColumnNames) // listColumnNames是你的列表字段名集合
    {
        var cell = new Cell
        {
            CellValue = new CellValue(columnName),
            DataType = CellValues.String,
            StyleIndex = 1 // 对应表头样式ID
        };
        headerRow.Append(cell);
    }
    sheetData.Append(headerRow);

    // 4. 写入数据行(从第2行开始)
    uint rowIndex = 2;
    foreach (var listItem in listItems) // listItems是你从CSOM获取的列表项集合
    {
        var dataRow = new Row { RowIndex = rowIndex };
        foreach (var value in listItem.FieldValues)
        {
            var cell = new Cell
            {
                CellValue = new CellValue(value.ToString()),
                DataType = CellValues.String,
                StyleIndex = 2 // 先默认应用奇数行样式,后续条件格式会覆盖偶数行
            };
            dataRow.Append(cell);
        }
        sheetData.Append(dataRow);
        rowIndex++;
    }

    // 5. 添加交替行条件格式
    AddAlternatingRowConditionalFormatting(
        worksheetPart.Worksheet,
        dataStartRow: 2,
        dataEndRow: rowIndex - 1,
        columnCount: (uint)listColumnNames.Count);

    worksheetPart.Worksheet.Save();
    workbookPart.Workbook.Save();
}
关键注意事项
  • 如果你的SharePoint站点使用了自定义主题,表头的蓝色RGB值可能需要调整,用取色器吸取原生导出Excel的表头颜色即可。
  • 使用条件格式而非逐行设置样式,不仅能适配任意行数,还能提升大数据量下的导出性能。
  • 代码中的样式ID要严格对应,比如表头样式是StyleIndex=1,偶数行格式ID是3,别搞混了。

内容的提问来源于stack exchange,提问作者munmun poddar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:16:51