[C#] 解决使用ClosedXML生成Excel报表丢失样式的两种方法

使用ClosedXML生成excel前, 如果在excel的template中提前设置好样式, 比如单元格颜色, 自动回行等, 之后再使用ClosedXML写入数据的时候会出现样式丢失的情况; 还有一种情况, 在已经设置好的样式excel中写入数据的时候, 发现第一样永远不会折行, 而从datatable的第二行开始写就没有问题.

解决办法: 样式丢失的问题尤其是第一行样式被覆盖的情况,不确定是不是其本身机制就是被覆盖掉了还是其实是ClosedXML的bug, 最后总结了两种曲线救国的办法(参考下面), 整体思路是复制已经设置好的报表格式的某一行, 之后copy到真正应该写入数据的行中, 之后再写入数据; 另一种是先写入数据, 之后再将base表格的样式copy到整体的数据行中.

方法1:

public byte[] ExportReport(Report obj)
{
    var result = _repository.GetRegisteredNum(obj);

    //copy a new file named with time
    string nowTimeStamp = GetTimeStamp();
    string basePath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    string path = basePath + Common.Constants.Template.LocalPath;

    string sourceFile = path + "ReportTemplate.xlsx";
    string destinationFile = sourceFile + nowTimeStamp + ".xlsx";

    File.Copy(sourceFile, destinationFile, false);
    string[] reportColumn = {"B", "C", "D", "E"};

    using (XLWorkbook wb = new XLWorkbook(destinationFile))
    {
        var ws = wb.Worksheet(1);
        int rowindex = 1;

        //foreach (var result in obj.OutstandingOLList)
        foreach (var resulta in result)
        {
            int row = 15 + result.IndexOf(resulta);
            var copyRows = ws.Row(13).AsRange();        // Always copy row 13 style to others row.
            var copyToRows = ws.Row(row).AsRange();

            copyRows.CopyTo(copyToRows);
            ws.Cell(row, "A").Value = rowindex++ ;
            ws.Cell(row, reportColumn[0]).Value = resulta.AValue;
            ws.Cell(row, reportColumn[1]).Value = resulta.BValue;
            ws.Cell(row, reportColumn[2]).Value = resulta.CValue;
            ws.Cell(row, reportColumn[3]).Value = resulta.DValue;
        }
        // delete origin row 13.
        ws.Row(13).Delete();
        
        using (var ms = new MemoryStream())
        {
            wb.SaveAs(ms);
            File.Delete(destinationFile);
            return ms.ToArray();
        }
    }
}

方法2:

public byte[] ExportReport2(Report obj)
{
    var result = _repository.GetRegisteredNum(obj);

    //copy a new file named with time
    string nowTimeStamp = GetTimeStamp();
    string basePath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    string path = basePath + Common.Constants.Template.LocalPath;

    string sourceFile = path + "ReportTemplate.xlsx";
    string destinationFile = sourceFile + nowTimeStamp + ".xlsx";

    File.Copy(sourceFile, destinationFile, false);
    string[] reportColumn = {"B", "C", "D", "E"};

    using (XLWorkbook wb = new XLWorkbook(destinationFile))
    {
        var ws = wb.Worksheet(1);
        int rowindex = 1;

        //foreach (var result in obj.OutstandingOLList)
        foreach (var resulta in result)
        {
            int row = 15 + result.IndexOf(resulta);
            // var copyRows = ws.Row(13).AsRange();        // Always copy row 13 style to others row.
            // var copyToRows = ws.Row(row).AsRange();

            copyRows.CopyTo(copyToRows);
            ws.Cell(row, "A").Value = rowindex++ ;
            ws.Cell(row, reportColumn[0]).Value = resulta.AValue;
            ws.Cell(row, reportColumn[1]).Value = resulta.BValue;
            ws.Cell(row, reportColumn[2]).Value = resulta.CValue;
            ws.Cell(row, reportColumn[3]).Value = resulta.DValue;
            
            for (int m = 0; m < 6; m++){
                // copy row 13 style to others row by 1 cell. 
                ws.Cell(row, reportColumn[m]).Style = ws.Cell(13 , reportColumn[m]).Style;
            }
        }
        
        // delete origin row 13. 
        ws.Row(13).Delete();
        
        using (var ms = new MemoryStream())
        {
            wb.SaveAs(ms);
            File.Delete(destinationFile);
            return ms.ToArray();
        }
    }
}

其他说明:

No.1  在上述代码中都有删除base line的代码操作(ws.Row(13).Delete();) , 如果是要删除多行可能会出现OutOfMemory errors, 或者删除不掉行的情况

解决办法:

Turning off events
By default ClosedXML keeps track of the inserts/deletes and adjusts the ranges accordingly.

For example:

var testRow = worksheet.Row(1);
worksheet.Row(1).InsertRowsAbove(1);
// testRow now points to the second row of the worksheet, not the first.

If you don't need this feature then you can turn it off to save memory and increase performance. Just open your workbook with the option XLEventTracking.Disabled.

var wb = new XLWorkbook(XLEventTracking.Disabled);

No.2  发生 Could not load file or assembly 'DocumentFormat.OpenXml' 异常

解决办法:

https://stackoverflow.com/questions/25307323/could-not-load-file-or-assembly-documentformat-openxml
https://www.microsoft.com/en-us/download/details.aspx?id=5124

除了版本问题外, 也要考虑是否在deploy的时候丢失了该类库.

本文原创由`bluetata`发布于blog.csdn.net、转载请务必注明出处。

Flag Counter

你可能感兴趣的:([01],C#,[05],踩坑记录)