diff --git a/ClosedXML/Excel/Ranges/XLRangeBase.cs b/ClosedXML/Excel/Ranges/XLRangeBase.cs index 0604aef..af93919 100644 --- a/ClosedXML/Excel/Ranges/XLRangeBase.cs +++ b/ClosedXML/Excel/Ranges/XLRangeBase.cs @@ -635,15 +635,19 @@ if (!cell.IsEmpty(true)) return cell; } } + } - var intersectedRanges = Worksheet.MergedRanges.GetIntersectedRanges(RangeAddress).ToList(); - if (intersectedRanges.Any()) - { - Int32 minRo = intersectedRanges.Min(r => r.RangeAddress.FirstAddress.RowNumber); - Int32 minCo = intersectedRanges.Min(r => r.RangeAddress.FirstAddress.ColumnNumber); + var intersectedRanges = Worksheet.MergedRanges.GetIntersectedRanges(RangeAddress) + .Where(r => predicate?.Invoke(r.FirstCell()) ?? true).ToList(); + if (intersectedRanges.Any()) + { + Int32 minRo = intersectedRanges.Min(r => r.RangeAddress.FirstAddress.RowNumber); + Int32 minCo = intersectedRanges.Min(r => r.RangeAddress.FirstAddress.ColumnNumber); - return Worksheet.Cell(minRo, minCo); - } + if (sp.Row.Between(1, minRo - 1)) minRo = sp.Row; + if (sp.Column.Between(1, minCo - 1)) minCo = sp.Column; + + return Worksheet.Cell(minRo, minCo); } if (sp.Row > 0) @@ -725,15 +729,19 @@ if (!cell.IsEmpty(true)) return cell; } } + } - var intersectedRanges = Worksheet.MergedRanges.GetIntersectedRanges(RangeAddress).ToList(); - if (intersectedRanges.Any()) - { - Int32 minRo = intersectedRanges.Max(r => r.RangeAddress.LastAddress.RowNumber); - Int32 minCo = intersectedRanges.Max(r => r.RangeAddress.LastAddress.ColumnNumber); + var intersectedRanges = Worksheet.MergedRanges.GetIntersectedRanges(RangeAddress) + .Where(r => predicate?.Invoke(r.FirstCell()) ?? true).ToList(); + if (intersectedRanges.Any()) + { + Int32 maxRo = intersectedRanges.Max(r => r.RangeAddress.LastAddress.RowNumber); + Int32 maxCo = intersectedRanges.Max(r => r.RangeAddress.LastAddress.ColumnNumber); - return Worksheet.Cell(minRo, minCo); - } + if (sp.Row > maxRo) maxRo = sp.Row; + if (sp.Column > maxCo) maxCo = sp.Column; + + return Worksheet.Cell(maxRo, maxCo); } if (sp.Row > 0) diff --git a/ClosedXML_Tests/Excel/Ranges/UsedAndUnusedCellsTests.cs b/ClosedXML_Tests/Excel/Ranges/UsedAndUnusedCellsTests.cs index abced23..990a249 100644 --- a/ClosedXML_Tests/Excel/Ranges/UsedAndUnusedCellsTests.cs +++ b/ClosedXML_Tests/Excel/Ranges/UsedAndUnusedCellsTests.cs @@ -145,5 +145,71 @@ Assert.AreEqual("A1:E2", used); } } + + [TestCase(true, "A1:D2", "A1")] + [TestCase(true, "A2:D2", "A2")] + [TestCase(true, "A1:D2", "A1", "B2")] + [TestCase(true, "B2:D3", "C3")] + [TestCase(true, "B2:F4", "F4")] + [TestCase(false, "A1:D2", "A1")] + [TestCase(false, "A2:D2", "A2")] + [TestCase(false, "A1:D2", "A1", "B2")] + [TestCase(false, "B2:D3", "C3")] + [TestCase(false, "B2:F4", "F4")] + public void RangeUsedIncludesMergedCells(bool includeFormatting, string expectedRange, + params string[] cellsWithValues) + { + using (XLWorkbook wb = new XLWorkbook()) + { + var ws = wb.AddWorksheet("Sheet1"); + foreach (var cellAddress in cellsWithValues) + { + ws.Cell(cellAddress).Value = "Not empty"; + } + ws.Range("B2:D2").Merge(); + + var actual = ws.RangeUsed(includeFormatting).RangeAddress; + + Assert.AreEqual(expectedRange, actual.ToString()); + } + } + + [Test] + public void LastCellUsedPredicateConsidersMergedRanges() + { + using (XLWorkbook wb = new XLWorkbook()) + { + var ws = wb.AddWorksheet("Sheet1"); + ws.Cell("A1").Style.Fill.BackgroundColor = XLColor.Red; + ws.Cell("A2").Style.Fill.BackgroundColor = XLColor.Yellow; + ws.Cell("A3").Style.Fill.BackgroundColor = XLColor.Green; + ws.Range("A1:C1").Merge(); + ws.Range("A2:C2").Merge(); + ws.Range("A3:C3").Merge(); + + var actual = ws.LastCellUsed(true, c => c.Style.Fill.BackgroundColor == XLColor.Yellow); + + Assert.AreEqual("C2", actual.Address.ToString()); + } + } + + [Test] + public void FirstCellUsedPredicateConsidersMergedRanges() + { + using (XLWorkbook wb = new XLWorkbook()) + { + var ws = wb.AddWorksheet("Sheet1"); + ws.Cell("A1").Style.Fill.BackgroundColor = XLColor.Red; + ws.Cell("A2").Style.Fill.BackgroundColor = XLColor.Yellow; + ws.Cell("A3").Style.Fill.BackgroundColor = XLColor.Green; + ws.Range("A1:C1").Merge(); + ws.Range("A2:C2").Merge(); + ws.Range("A3:C3").Merge(); + + var actual = ws.FirstCellUsed(true, c => c.Style.Fill.BackgroundColor == XLColor.Yellow); + + Assert.AreEqual("A2", actual.Address.ToString()); + } + } } }