Excel 导出的仅 C# OpenXML 特定单元格样式

C# OpenXML-only specific cell styling for Excel export

我对 C# 比较陌生。以下是我目前拥有的代码。它适用于将 DataTable 转换为 Excel 格式的可导出字节数组。我首先在填充的 DataSet 上调用 Create(),将其存储在 Byte[] 中,然后由 DataSet 中的数据填充。请注意,下面的所有代码都可以完美运行,我希望根据特定条件向导出的 excel 文件添加一些样式。我想知道这样的 'if'(?) 语句可以去哪里,因为我可以在什么地方附加这个样式信息,考虑到我的特定约束(我应该识别特定行中的数据并突出显示它们。)我我在网上尝试了很多资源,考虑到我正在使用的实现,几乎每一个都存在问题。我也不允许使用标准 OpenXML 之外的任何库。

    public static Byte[] Create(DataSet ds)
    {
        Dictionary<String, List<OpenXmlElement>> sets = ToSheets(ds);
        Byte[] _data = new Byte[] { };

        using (MemoryStream _ms = new MemoryStream())
        {
            using (SpreadsheetDocument package = SpreadsheetDocument.Create(_ms, SpreadsheetDocumentType.Workbook))
            {
                WorkbookPart workbookpart = package.AddWorkbookPart();
                workbookpart.Workbook = new Workbook();

                Sheets sheets = workbookpart.Workbook.AppendChild(new Sheets());
                foreach (KeyValuePair<String, List<OpenXmlElement>> set in sets)
                {
                    WorksheetPart worksheetpart = workbookpart.AddNewPart<WorksheetPart>();
                    worksheetpart.Worksheet = new Worksheet(new SheetData(set.Value));
                    worksheetpart.Worksheet.Save();

                    Sheet sheet = new Sheet()
                    {
                        Id = workbookpart.GetIdOfPart(worksheetpart),
                        SheetId = Convert.ToUInt32(sheets.Count() + 1),
                        Name = set.Key
                    };
                    sheets.AppendChild(sheet);
                }
                workbookpart.Workbook.Save();
            }
            _data = _ms.ToArray();
        }
        return _data;
    }

上面是主要的 Create() 函数,下面是 ToSheets() 函数。它应该是不言自明的。

    public static Dictionary<String, List<OpenXmlElement>> ToSheets(DataSet ds)
    {
        return
            (from dt in ds.Tables.OfType<DataTable>()
             select new
             {
                 Key = dt.TableName,
                 Value = (
                 new List<OpenXmlElement>(
                    new OpenXmlElement[] 
            {
                new Row(
                    from d in dt.Columns.OfType<DataColumn>()
                    select (OpenXmlElement)new Cell()
                    {
                        CellValue = new CellValue(d.ColumnName),
                        DataType = CellValues.String
                    })
            })).Union
                 ((from dr in dt.Rows.OfType<DataRow>()
                   select ((OpenXmlElement)new Row(from dc in dr.ItemArray
                                                   select (OpenXmlElement)new Cell()
                                                   {
                                                       CellValue = new CellValue(dc.ToString()),
                                                       DataType = CellValues.String
                                                   })))).ToList()
             }).ToDictionary(p => p.Key, p => p.Value);
    }

如果有人能为我指出正确的方向,我将不胜感激,因为我可以在何处附加样式信息以及如何去做(记住我必须根据行中的数据设置行样式,即. 具有特定单元格值的行应该以特定方式设置该行的样式。)具体来说,当所述行中的第一个单元格包含数据时,我希望为具有蓝色背景且无边框的行中的单元格设置样式,比如 "X".

感谢您的宝贵时间!

我设法自己解决了这个问题。我在 this page.

中添加了详细的样式信息

然后我修改了自己的代码以反映选择性更改。

    public Dictionary<String, List<OpenXmlElement>> ToSheets(DataSet ds)
    {
        return
            (from dt in ds.Tables.OfType<DataTable>()
             select new
             {
                 Key = dt.TableName,
                 Value = (
                 new List<OpenXmlElement>(
                    new OpenXmlElement[] 
            {
                new Row(
                    from d in dt.Columns.OfType<DataColumn>()
                    select (OpenXmlElement)new Cell()
                    {
                        CellValue = new CellValue(d.ColumnName),
                        StyleIndex = 1,
                        DataType = CellValues.String
                    })
            })).Union
                 ((from dr in dt.Rows.OfType<DataRow>()
                   select ((OpenXmlElement)new Row(from dc in dr.ItemArray
                                                   select (OpenXmlElement)new Cell()
                                                   {
                                                       CellValue = new CellValue(dc.ToString()),
                                                       DataType = CellValues.String,
                                                       StyleIndex = styleIdentifier(dc.ToString())
                                                   })))).ToList()
             }).ToDictionary(p => p.Key, p => p.Value);
    }

很明显,我使用上面的链接指南通过将多个子级附加到 stylesPart.Stylesheet.CellFormats 来定义多个 StyleIndex 值。有效!然后我简单地使用下面的函数来动态识别我想为每个特定行附加的样式信息。

    public UInt32Value styleIdentifier(String str)
    {
        int temp;

        xCount.Value = (Convert.ToInt32(this.xCount.Value) + 1).ToString();

        if (int.TryParse(str, out temp))
        { xCount.Value = "0"; }

        if (Convert.ToInt32(this.xCount.Value) < 4)
        { return 2; }

        return 3;
    }

在 code-front 方面,我只是将 "xCount" 用作初始值 >5 的 HiddenField 值。 这样,对于从第 1 列的数据中识别为要突出显示的行的每一行,每个单元格都会突出显示(最多 4 个,假设我有 4 列)。然后重置 xCount 的值,直到遇到另一个这样的单元格,然后重复该过程,直到遇到下一个 to-be-highlighted 行。

再次感谢 Whosebug 聊天室的好心人,特别是@juanvan 指导我正确的方向!