具有纯色的C#EPPlus数据栏条件格式

时间:2018-10-02 01:34:43

标签: c# excel xml epplus conditional-formatting

我正在生成包含几列百分比数据的excel报告。由于这些报告仅用于演示目的,因此我想通过使用带有实心填充的数据栏设置百分比数据的格式来使其看起来更美观。事实证明,这非常困难,因为EPPlus中没有直接设置数据栏的实心填充,但是尽管如此,我还是得出了这篇文章的答案:

Inconsistent appearance between manual and coded versions of solid databar and databar minimum value

但是,无论我多么努力为我的应用程序编辑代码,我只有一栏最后以实心填充,其余为渐变。即使我将问题中的节点更改为如下所示的节点列表:

        var cfNodes = xdoc.SelectNodes("/default:worksheet/default:conditionalFormatting/default:cfRule", nsm);
        foreach(XmlNode cfNode in cfNodes)
        {
            cfNode.AppendChild(extLstCf);
        }

以及工作表元素:

        var wsNodes = xdoc.SelectNodes("/default:worksheet", nsm);
        foreach(XmlElement wsNode in wsNodes)
        {
            wsNode.AppendChild(extLstWs);
        }

我也尝试过使用xml来更改<sqref>参数,但这仍然不能覆盖我的所有数据栏列。我认为必须可以在xml中进行某些更改以完成我想要的操作,但是我不知道要寻找什么...

2 个答案:

答案 0 :(得分:0)

好家伙,我花了几天的时间,但我终于想通了。可能有一种更简单的方法可以做到这一点,但到目前为止,这就是我让它为我工作的方式:

需要在工作表级别节点上附加一个工作表xml扩展列表节点,该节点包括工作表中包含的数字数据栏元素,并且每个元素都必须具有gradient = 0才能用于实体填充I。例如,工作表包含两个数据栏,所以我的看起来像这样:

        var extLstWs = xdoc.CreateNode(XmlNodeType.Element, "extLst", xdoc.DocumentElement.NamespaceURI);
        extLstWs.InnerXml = @"<ext uri=""{78C0D931-6437-407d-A8EE-F0AAD7539E65}"" 
                                        xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
                                    <x14:conditionalFormattings>
                                    <x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
                                    <x14:cfRule type=""dataBar"" id=""{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}"">
                                        <x14:dataBar minLength=""0"" maxLength=""100"" gradient=""0"">
                                        <x14:cfvo type=""num"">
                                            <xm:f>0</xm:f>
                                        </x14:cfvo>
                                        <x14:cfvo type=""num"">
                                            <xm:f>100</xm:f>
                                        </x14:cfvo>
                                        <x14:negativeFillColor rgb=""FFFF0000""/><x14:axisColor rgb=""FF000000""/>
                                        </x14:dataBar>
                                    </x14:cfRule>
                                    <xm:sqref>A1:A20</xm:sqref>
                                    </x14:conditionalFormatting>
                                    <x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
                                        <x14:cfRule type=""dataBar"" id=""{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}"">
                                        <x14:dataBar minLength=""0"" maxLength=""100"" gradient=""0"">
                                            <x14:cfvo type=""num"">
                                            <xm:f>0</xm:f>
                                            </x14:cfvo><x14:cfvo type=""num"">
                                            <xm:f>200</xm:f>
                                            </x14:cfvo><x14:negativeFillColor rgb=""FFFF0000""/>
                                            <x14:axisColor rgb=""FF000000""/>
                                        </x14:dataBar>
                                        </x14:cfRule>
                                        <xm:sqref>B1:B20</xm:sqref>
                                    </x14:conditionalFormatting>
                                    </x14:conditionalFormattings>
                                </ext>";
        var wsNode = xdoc.SelectSingleNode("/default:worksheet", nsm);
        wsNode.AppendChild(extLstWs);

请注意,我是如何在其中获得<x14:conditionalFormattings>的两个子节点的,每个数据栏一个。

第二个条件格式化规则节点的扩展列表需要附加在<cfRule>节点下,每个数据栏也要附加一个扩展列表。我能够使用foreach循环在我的工作表中找到所有数据栏,并将相同的xml附加到每个数据栏中,如下所示:

        var cfNodes = xdoc.SelectNodes("/default:worksheet/default:conditionalFormatting/default:cfRule", nsm);
        foreach (XmlNode cfnode in cfNodes)
        {
            var extLstCfNormal = xdoc.CreateNode(XmlNodeType.Element, "extLst", xdoc.DocumentElement.NamespaceURI);
            extLstCfNormal.InnerXml = @"<ext uri=""{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"" 
                            xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
                            <x14:id>{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}</x14:id></ext>";

            cfnode.AppendChild(extLstCfNormal);
        }

完成上述操作后,我终于能够用实心填充显示所有数据栏。

答案 1 :(得分:0)

这是我的版本,该方法如何使那些无法应用Aowei Xu解决方案的人(例如我)可靠地填充数据栏。

public static Random Rnd = new Random();

public static string GenerateXlsId()
{
    //{29BD882A-B741-482B-9067-72CC5D939236}

    string id = string.Empty;

    for (int i = 0; i < 32; i++)
        if (Rnd.NextDouble() < 0.5)
            id += Rnd.Next(0, 10);
        else
            id += (char)Rnd.Next(65, 91);

    id = id.Insert(8, "-");
    id = id.Insert(13, "-");
    id = id.Insert(18, "-");
    id = id.Insert(23, "-");

    return id;
}

public static void FixDatabarsAtWorksheet(OfficeOpenXml.ExcelWorksheet eworksheet)
{
    System.Xml.XmlNodeList databars = eworksheet.WorksheetXml.GetElementsByTagName("dataBar");

    if (databars.Count > 0)
    {
        string conditional_formattings_str = string.Empty;

        for (int i = 0; i < databars.Count; i++)
        {
            string temp_databar_id = GenerateXlsId();

            databars[i].ParentNode.InnerXml += @"<extLst>
        <ext uri=""{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"" xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
            <x14:id>{" + temp_databar_id + @"}</x14:id>
        </ext>
    </extLst>";
            //--

            string temp_sqref = databars[i].ParentNode.ParentNode.Attributes["sqref"].Value;
            string left_type = string.Empty;
            string left_val = string.Empty;
            string right_type = string.Empty;
            string right_val = string.Empty;
            string color = string.Empty;
            Color databar_fill_color = Color.Empty;
            Color databar_border_color = Color.Empty;

            for (int j = 0; j < databars[i].ChildNodes.Count; j++)
                if (databars[i].ChildNodes[j].LocalName == "cfvo" && databars[i].ChildNodes[j].Attributes["type"] != null)
                {
                    if (string.IsNullOrEmpty(left_type))
                        left_type = databars[i].ChildNodes[j].Attributes["type"].Value;
                    else if (string.IsNullOrEmpty(right_type))
                        right_type = databars[i].ChildNodes[j].Attributes["type"].Value;

                    if (databars[i].ChildNodes[j].Attributes["val"] != null)
                        if (string.IsNullOrEmpty(left_val))
                            left_val = databars[i].ChildNodes[j].Attributes["val"].Value;
                        else if (string.IsNullOrEmpty(right_val))
                            right_val = databars[i].ChildNodes[j].Attributes["val"].Value;
                }
                else if (databars[i].ChildNodes[j].LocalName == "color")
                {
                    color = databars[i].ChildNodes[j].Attributes["rgb"].Value;
                    int argb = Int32.Parse(color, System.Globalization.NumberStyles.HexNumber);
                    databar_fill_color = Color.FromArgb(argb);

                    databar_border_color = Color.FromArgb(255,
                        databar_fill_color.R - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.R - 50,
                        databar_fill_color.G - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.G - 50,
                        databar_fill_color.B - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.B - 50);
                }

            string temp_conditional_formatting_template = @"<x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
        <x14:cfRule type=""dataBar"" id=""{" + temp_databar_id + @"}"">
            <x14:dataBar minLength=""" + (string.IsNullOrEmpty(left_val) ? "0" : left_val) + "\" maxLength=\"" + (string.IsNullOrEmpty(right_val) ? "100" : right_val) + "\" gradient=\"0\" " + (databar_border_color.IsEmpty ? string.Empty : "border = \"1\"") + ">";

            temp_conditional_formatting_template += Environment.NewLine + "<x14:cfvo type=\"" + (left_type.ToLower() == "min" ? "autoMin" : left_type) + "\" />";
            temp_conditional_formatting_template += Environment.NewLine + "<x14:cfvo type=\"" + (right_type.ToLower() == "max" ? "autoMax" : right_type) + "\" />";

            if (!databar_border_color.IsEmpty)
                temp_conditional_formatting_template += Environment.NewLine + "<x14:borderColor rgb=\"" + BitConverter.ToString(new byte[] { databar_border_color.A, databar_border_color.R, databar_border_color.G, databar_border_color.B }).Replace("-", "") + "\" />";

            temp_conditional_formatting_template += Environment.NewLine + @"</x14:dataBar>
        </x14:cfRule>
        <xm:sqref>" + temp_sqref + @"</xm:sqref>
    </x14:conditionalFormatting>";

            conditional_formattings_str += temp_conditional_formatting_template;
        }

        databars[0].ParentNode.ParentNode.ParentNode.InnerXml += @"<extLst>
<ext uri=""{78C0D931-6437-407d-A8EE-F0AAD7539E65}"" xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
<x14:conditionalFormattings>" + conditional_formattings_str + @" 
</x14:conditionalFormattings>
</ext>
</extLst>";
    }
}

这么小的东西真是太痛苦了……瓜哇阿阿arr r r r!

P.S。 MS ,我讨厌XmlElements在将它们插入父节点时跳过前缀值!

P.S.2。这使得其他任何条件格式都消失了...不知道为什么... OMG!