使用EPPlus复制/克隆Excel图表

时间:2017-05-06 05:27:53

标签: c# epplus

我在我的项目中使用EPPlus,我知道你可以复制现有的Shape,但是没有复制现有Chart的方法。

我已经设置了一个带有模板图表的工作簿,我需要复制并更新系列以指向不同的数据表/集。

我可以毫无后顾之忧地填充数据,并可以创建新的图表,但随后需要大小,位置和样式。只需克隆图表模板并修改系列和位置以简化代码就会轻松得多。

目前我使用这种方法:

// wb is an ExcelWorkbook
ExcelWorksheet ws = wb.Worksheets[sheetIdx];
ExcelChart chart = (ExcelChart)ws.Drawings[0];
ExcelChart cc = ws.Drawings.AddChart("Chart " + (i + 2), eChartType.ColumnClustered);

// invoke methods that will position and size new chart

// copy starting chart xml so will have identical styling, series, legend etc
var xml = XDocument.Parse(chart.ChartXml.InnerXml);
XNamespace nsC = "http://schemas.openxmlformats.org/drawingml/2006/chart";
XNamespace nsA = "http://schemas.openxmlformats.org/drawingml/2006/main";

// modify xml to update Category, Title and Values formulas
var fs = xml.Descendants(nsC + "f");
foreach (var f in fs)
{
    f.Value = ws.Cells[f.Value].Offset(chartNumRows + 1, 0).FullAddressAbsolute;
}

// set new chart xml to modified xml.
cc.ChartXml.InnerXml = xml.ToString();

哪个有效,但有几个缺点。

1)克隆(我的例子中的cc)的chart.series尚未设置,在代码中查看是因为它仅在对象构造期间完成。如果我可以更新此属性,那么我将能够轻松解决第二个问题

2)我需要删除所有系列并添加新系列,因为系列属性未正确初始化,这比应该更难。

任何有助于在图表中初始化属性的帮助或更好的克隆原始方法的方法将不胜感激!

1 个答案:

答案 0 :(得分:0)

似乎没有内置功能,我可以想出的其他重新加载方法需要对 EPPlus 源进行太多更改,因此在找到更好的解决方案之前,我已将以下方法添加到 EPPlus\绘图\ExcelDrawings.cs

public ExcelChart CloneChart(ExcelChart SourceChart, String NewName)
{
    // Create clone
    var tempClone = this.AddChart(NewName, SourceChart.ChartType, null);
    tempClone.ChartXml.InnerXml = SourceChart.ChartXml.InnerXml;

    // Reload clone
    using (tempClone.Part.Stream = new MemoryStream())
    {
        // Create chart object using temps package and xml
        var chartXmlBytes = Encoding.ASCII.GetBytes(tempClone.ChartXml.OuterXml);
        tempClone.Part.Stream.Write(chartXmlBytes, 0, chartXmlBytes.Length);
        var finalClone = ExcelChart.GetChart(this, tempClone.TopNode);

        // Remove old from collection
        var index = _drawingNames[tempClone.Name];
        var draw = _drawings[index];
        for (int i = index + 1; i < _drawings.Count; i++)
            _drawingNames[_drawings[i].Name]--;
        _drawingNames.Remove(draw.Name);
        _drawings.Remove(draw);

        // Add new to collection
        finalClone.Name = tempClone.Name;
        _drawings.Add(finalClone);
        _drawingNames.Add(finalClone.Name, _drawings.Count - 1);

        // Done
        return finalClone;
    }
}
相关问题