diff --git a/src/EPPlus/Style/Dxf/DxfStyleHandler.cs b/src/EPPlus/Style/Dxf/DxfStyleHandler.cs index e830f4440..5da4198c1 100644 --- a/src/EPPlus/Style/Dxf/DxfStyleHandler.cs +++ b/src/EPPlus/Style/Dxf/DxfStyleHandler.cs @@ -210,7 +210,9 @@ private static void UpdateConditionalFormatting(ExcelWorksheet ws, ExcelStyleCol { foreach (var cf in ws.ConditionalFormatting) { - if (cf.Style.HasValue) + //If at least one border exists then a dxf style for the border must be added even if the value for that border is empty + //(Thus meaning HasValue is false) + if (cf.Style.HasValue || cf.Style.Border != null && cf.Style.Border.AtLeastOneBorderExists()) { var standardDxfStyle = cf.Style.ToDxfStyle(); @@ -228,11 +230,9 @@ private static void UpdateConditionalFormatting(ExcelWorksheet ws, ExcelStyleCol { ((ExcelConditionalFormattingRule)cf).DxfId = ix; cf.Style.DxfId = ix; - //cf.Style.DxfId = ix; } } } - //var num = dxfs._list[129]; } internal static void CopyDxfStylesTable(ExcelTable tblFrom, ExcelTable tblTo) { diff --git a/src/EPPlus/Style/Dxf/ExcelDxfBorder.cs b/src/EPPlus/Style/Dxf/ExcelDxfBorder.cs index 5b51e8a3c..2b369f188 100644 --- a/src/EPPlus/Style/Dxf/ExcelDxfBorder.cs +++ b/src/EPPlus/Style/Dxf/ExcelDxfBorder.cs @@ -205,14 +205,36 @@ internal override DxfStyleBase Clone() Horizontal = (ExcelDxfBorderItem)Horizontal.Clone(), }; } + + private bool BorderItemExists(ExcelDxfBorderItem bi) + { + if (bi.Style != null) + { + return true; + } + return false; + } + + internal bool AtLeastOneBorderExists() + { + if (BorderItemExists(Left)) return true; + if (BorderItemExists(Right)) return true; + if (BorderItemExists(Bottom)) return true; + if (BorderItemExists(Top)) return true; + if (BorderItemExists(Vertical)) return true; + if (BorderItemExists(Horizontal)) return true; + + return false; + } + internal override void SetValuesFromXml(XmlHelper helper) { if (helper.ExistsNode("d:border")) { Left = GetBorderItem(helper, "d:border/d:left", eStyleClass.BorderLeft); - Right = GetBorderItem(helper, "d:border/d:right", eStyleClass.BorderLeft); - Bottom = GetBorderItem(helper, "d:border/d:bottom", eStyleClass.BorderLeft); - Top = GetBorderItem(helper, "d:border/d:top", eStyleClass.BorderLeft); + Right = GetBorderItem(helper, "d:border/d:right", eStyleClass.BorderRight); + Bottom = GetBorderItem(helper, "d:border/d:bottom", eStyleClass.BorderBottom); + Top = GetBorderItem(helper, "d:border/d:top", eStyleClass.BorderTop); Vertical = GetBorderItem(helper, "d:border/d:vertical", eStyleClass.Border); Horizontal = GetBorderItem(helper, "d:border/d:horizontal", eStyleClass.Border); } @@ -224,7 +246,8 @@ private ExcelDxfBorderItem GetBorderItem(XmlHelper helper, string path, eStyleCl if (exists) { var style = helper.GetXmlNodeString(path + "/@style"); - bi.Style = GetBorderStyleEnum(style); + //When exists and border has no style the CT_BorderPr\ST_BorderStyle node defaults to BorderNone if the node exists even when empty + bi.Style = GetBorderStyleEnum(style) ?? ExcelBorderStyle.None; bi.Color = GetColor(helper, path + "/d:color", styleClass); } return bi; diff --git a/src/EPPlus/Style/Dxf/ExcelDxfStyleLimitedFont.cs b/src/EPPlus/Style/Dxf/ExcelDxfStyleLimitedFont.cs index 4e5a15ae7..08a4d370e 100644 --- a/src/EPPlus/Style/Dxf/ExcelDxfStyleLimitedFont.cs +++ b/src/EPPlus/Style/Dxf/ExcelDxfStyleLimitedFont.cs @@ -52,7 +52,7 @@ internal override void CreateNodes(XmlHelper helper, string path) { if (Font.HasValue) Font.CreateNodes(helper, "d:font"); if (Fill.HasValue) Fill.CreateNodes(helper, "d:fill"); - if (Border.HasValue) Border.CreateNodes(helper, "d:border"); + if (Border.HasValue || Border.AtLeastOneBorderExists()) Border.CreateNodes(helper, "d:border"); } /// /// If the object has any properties set diff --git a/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs b/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs index baba29937..e7d47de04 100644 --- a/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs +++ b/src/EPPlusTest/Issues/ConditionalFormattingIssues.cs @@ -7,6 +7,8 @@ using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; +using System.Runtime.InteropServices; using System.Threading; namespace EPPlusTest.Issues @@ -262,6 +264,127 @@ public void RoundTrip_ExtIconSetWithNumericFormulaCfvo_DoesNotThrow() } } + + [TestMethod] + public void ReadEppGeneratedCFBorderStylesCorrectly() + { + using (var p = OpenPackage("i2488_EppGen.xlsx", true)) + { + var ws = p.Workbook.Worksheets.Add("readBorderNone"); + + var notEqual = ws.Cells["C1:C5"].ConditionalFormatting.AddNotEqual(); + + notEqual.Formula = "1"; + + ws.Cells["D5"].Style.Border.Left.Style = ExcelBorderStyle.None; + + //Set a borderstyle to thick so that Conditional Formatting can then Set it to None + ws.Cells["C2"].Style.Border.Left.Style = ExcelBorderStyle.Thick; + ws.Cells["C2"].Style.Border.Top.Style = ExcelBorderStyle.Thick; + ws.Cells["C2"].Style.Border.Right.Style = ExcelBorderStyle.Thick; + ws.Cells["C2"].Style.Border.Bottom.Style = ExcelBorderStyle.Thick; + + notEqual.Style.Border.Left.Style = ExcelBorderStyle.None; + notEqual.Style.Border.Top.Style = ExcelBorderStyle.None; + notEqual.Style.Border.Right.Style = ExcelBorderStyle.None; + notEqual.Style.Border.Bottom.Style = ExcelBorderStyle.None; + + SaveAndCleanup(p); + } + using (var p = OpenPackage("i2488_EppGen.xlsx", false)) + { + var ws = p.Workbook.Worksheets[0]; + var cfs = ws.Cells["C1:C5"].ConditionalFormatting.GetConditionalFormattings(); + + var rightStyle = cfs[0].Style.Border.Right.Style; + Assert.AreEqual(ExcelBorderStyle.None, ws.Cells["D5"].Style.Border.Left.Style); + //Assert that we can read borderStyle None. This is different from NoNode and the same as an Empty border node + Assert.AreEqual(ExcelBorderStyle.None, cfs[0].Style.Border.Right.Style); + Assert.AreEqual(ExcelBorderStyle.None, cfs[0].Style.Border.Left.Style); + Assert.AreEqual(ExcelBorderStyle.None, cfs[0].Style.Border.Top.Style); + Assert.AreEqual(ExcelBorderStyle.None, cfs[0].Style.Border.Bottom.Style); + } + } + + /// + /// Epplus did not write out ExcelBorderStyle.None correctly into DXF styles + /// Causing Cell-Styling to be applied instead of the conditionallyFormatted "None" style + /// + [TestMethod] + public void CopyingIssue2488_ActualCase() + { + string expectedId = ""; + var fi = GetOutputFile("", "i2488_out.xlsx"); + var copiedName = ""; + + using (var p = OpenTemplatePackage("i2488.xlsx")) + { + var wkbook = p.Workbook; + var wkSheet = wkbook.Worksheets[0]; + + var conditionalFormatting = wkSheet.Cells["S15"].ConditionalFormatting.GetConditionalFormattings().First(cf => cf.Address.Address == "S7:Y22"); + var dxfId = conditionalFormatting.DxfId; + expectedId = conditionalFormatting.Style.ToDxfStyle().Id; + Assert.AreEqual(expectedId, wkbook.Styles.Dxfs[dxfId].Id); + var sheetName = wkSheet.Name; + var copyCount = 1; + + copiedName = $"{sheetName}_{1}"; + + for (int i = 1; i <= copyCount; i++) + { + p.Workbook.Worksheets.Copy( + wkSheet.Name, $"{sheetName}_{i}"); + } + + wkSheet = wkbook.Worksheets[1]; + sheetName = wkbook.Worksheets[1].Name; + + for (int i = 1; i <= copyCount; i++) + { + p.Workbook.Worksheets.Copy( + wkSheet.Name, $"{sheetName}_{i}"); + } + p.SaveAs(fi); + } + using (var p = OpenPackage(fi.Name, false)) + { + var wkbook = p.Workbook; + var wkSheet = wkbook.Worksheets[copiedName]; + + var conditionalFormatting = wkSheet.Cells["S15"].ConditionalFormatting.GetConditionalFormattings().First(cf => cf.Address.Address == "S7:Y22"); + Assert.AreEqual(expectedId, conditionalFormatting.Style.ToDxfStyle().Id); + } + } + + [TestMethod] + public void CopyingIssue2488_StyleRead() + { + string expectedId = ""; + var fi = GetOutputFile("", "i2488_Read_out.xlsx"); + + using (var p = OpenTemplatePackage("i2488.xlsx")) + { + var wkbook = p.Workbook; + var wkSheet = wkbook.Worksheets[0]; + + var conditionalFormatting = wkSheet.Cells["S15"].ConditionalFormatting.GetConditionalFormattings().First(cf=> cf.Address.Address == "S7:Y22"); + var dxfId = conditionalFormatting.DxfId; + expectedId = conditionalFormatting.Style.ToDxfStyle().Id; + Assert.AreEqual(expectedId, wkbook.Styles.Dxfs[dxfId].Id); + p.SaveAs(fi); + } + + using (var p = OpenPackage(fi.Name, false)) + { + var wkbook = p.Workbook; + var wkSheet = wkbook.Worksheets[0]; + + var conditionalFormatting = wkSheet.Cells["S15"].ConditionalFormatting.GetConditionalFormattings().First(cf => cf.Address.Address == "S7:Y22"); + Assert.AreEqual(expectedId, conditionalFormatting.Style.ToDxfStyle().Id); + } + } + [TestMethod] public void RoundTrip_RegularIconSetWithNumericFormulaCfvo_DoesNotThrow() {