When applying cell protection to a Range, this is handled on a cell-by-cell basis. That is very inefficient for large ranges.
For example the following test produces an OutOfMemoryException on my machine. The test sets the first 6 columns of the sheet to be protected. The way ClosedXML does this is to enumerate each cell in the range, then set the protection style. And because each column is considered as a range with 1048576 cells, this requires a lot of processing.
When doing this in Excel or LibreOffice, it's fast and the resulting file is small. So apparently there is a way to do it more efficiently.
Possibly this issue applies to other types of styling as well (e.g. setting the background of a whole column), that should be tested further.
```
using ClosedXML.Excel;
using NUnit.Framework;
namespace ClosedXML_Tests
{
[TestFixture]
public class LargeRangeTests
{
[Test]
public void CanCreateLargeRange()
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
var range = ws1.Range("A:F");
Assert.AreEqual(range.LastRow().RowNumber(), 1048576, "Row number of last row");
range.Style.Protection.Locked = true;
Assert.True(range.LastRow().Style.Protection.Locked, "Last row is locked");
}
}
}
```
Update: it applies to other forms of styling as well, like setting the background of the whole column. The test below also leads to an OutOfMemoryException.
```
[Test]
public void CanSetColumnsBackground()
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
var range = ws1.Range("A:F");
Assert.AreEqual(range.LastRow().RowNumber(), 1048576, "Row number of last row");
range.Style.Fill.BackgroundColor = XLColor.RadicalRed;
Assert.AreEqual(range.LastRow().Style.Fill.BackgroundColor, XLColor.RadicalRed, "Last row is red");
}
```
Comments: For practical purposes, don't use Ranges when you want to style/protect a whole column. Like this it works just fine:
```
var columns = ws1.Columns(1, 6);
columns.Style.Fill.BackgroundColor = XLColor.RadicalRed;
```
Basically the way I used ClosedXML triggered the inefficiency. Cases like I mentioned could be solved more efficiently (i.e. handling a range like "A:F" on column-by-column basis, not cell-by-cell), but I think for most practical purposes there is a good way to achieve the desired result by using the right functions.
Complete tests added for posterity:
```
using ClosedXML.Excel;
using NUnit.Framework;
namespace ClosedXML_Tests
{
[TestFixture]
public class LargeRangeTests
{
[Test]
[ExpectedException(ExpectedException = typeof(System.OutOfMemoryException))]
public void CanSetColumnsProtectedWithRange()
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
var range = ws1.Range("A:F");
Assert.AreEqual(range.LastRow().RowNumber(), 1048576, "Row number of last row");
range.Style.Protection.Locked = true;
Assert.True(range.LastRow().Style.Protection.Locked, "Last row is locked");
}
[Test]
[ExpectedException(ExpectedException = typeof(System.OutOfMemoryException))]
public void CanSetColumnsBackgroundWithRange()
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
var range = ws1.Range("A:F");
Assert.AreEqual(range.LastRow().RowNumber(), 1048576, "Row number of last row");
range.Style.Fill.BackgroundColor = XLColor.RadicalRed;
Assert.AreEqual(range.LastRow().Style.Fill.BackgroundColor, XLColor.RadicalRed, "Last row is red");
}
[Test]
public void CanSetColumnsBackground()
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
var columns = ws1.Columns(1, 6);
columns.Style.Fill.BackgroundColor = XLColor.RadicalRed;
Assert.AreEqual(ws1.Cell(1048576, 1).Style.Fill.BackgroundColor, XLColor.RadicalRed, "Last cell is red");
}
}
}
```