用于Excel导出的C#OpenXML专用单元样式

时间:2016-01-19 23:45:54

标签: c# excel openxml openxml-sdk

我对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”。

感谢您的时间!

1 个答案:

答案 0 :(得分:0)

我自己设法解决了这个问题。我添加了样式信息,详见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;
    }

在代码正面,我只使用“xCount”作为HiddenField值,初始值> 5。 这样,对于从第1列中的数据标识为要突出显示的行的每一行,每个单元格都会突出显示(最多4个,因为我有4列)。然后重置xCount的值,直到遇到另一个这样的单元格并重复该过程,直到它遇到下一个要突出显示的行。

再次感谢StackOverflow聊天中的优秀人士,尤其是@juanvan引导我走向正确的方向!