NanoXLSX.Core 3.2.1
Loading...
Searching...
No Matches
Worksheet.cs
1/*
2 * NanoXLSX is a small .NET library to generate and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way
3 * Copyright Raphael Stoeckli © 2026
4 * This library is licensed under the MIT License.
5 * You find a copy of the license in project folder or on: http://opensource.org/licenses/MIT
6 */
7
8using System;
9using System.Collections.Generic;
10using System.Linq;
11using System.Text;
12using System.Text.RegularExpressions;
17using NanoXLSX.Styles;
18using NanoXLSX.Utils;
20
21namespace NanoXLSX
22{
26 public class Worksheet
27 {
28 static Worksheet()
29 {
31 }
32
33 #region constants
37 public static readonly int MaxWorksheetNameLength = 31;
41 public static readonly float DefaultWorksheetColumnWidth = 10f;
45 public static readonly float DefaultWorksheetRowHeight = 15f;
49 public static readonly int MaxColumnNumber = 16383;
53#pragma warning disable CA1805 // Do not initialize unnecessarily
54 public static readonly int MinColumnNumber = 0;
55#pragma warning restore CA1805
59#pragma warning disable CA1805 // Do not initialize unnecessarily
60 public static readonly float MinColumnWidth = 0f;
61#pragma warning restore CA1805
65#pragma warning disable CA1805 // Do not initialize unnecessarily
66 public static readonly float MinRowHeight = 0f;
67#pragma warning restore CA1805
71 public static readonly float MaxColumnWidth = 255f;
75 public static readonly int MaxRowNumber = 1048575;
79#pragma warning disable CA1805 // Do not initialize unnecessarily
80 public static readonly int MinRowNumber = 0;
81#pragma warning restore CA1805
85 public static readonly float MaxRowHeight = 409.5f;
89#pragma warning disable CA1805 // Do not initialize unnecessarily
90 public const int AutoZoomFactor = 0;
91#pragma warning restore CA1805
95 public const int MinZoomFactor = 10;
99 public const int MaxZoomFactor = 400;
100 //TODO remove with next major release
104 [Obsolete("Use MaxZoomFactor instead.")]
105 public const int maxZoomFactor = MaxZoomFactor;
106 #endregion
107
108 #region enums
121
159
174
187 #endregion
188
189 #region privateFields
190 private Style activeStyle;
191 private Range? autoFilterRange;
192 private readonly Dictionary<CellKey, Cell> cells;
193 private readonly StringKeyedCellView cellsStringView;
194 private readonly Dictionary<int, Column> columns;
195 private string sheetName;
196 private int currentRowNumber;
197 private int currentColumnNumber;
198 private float defaultRowHeight;
199 private float defaultColumnWidth;
200 private readonly Dictionary<int, float> rowHeights;
201 private readonly Dictionary<int, bool> hiddenRows;
202 private readonly Dictionary<string, Range> mergedCells;
203 private readonly List<SheetProtectionValue> sheetProtectionValues;
204 private bool useActiveStyle;
205 private bool hidden;
206 private Workbook workbookReference;
207 private IPassword sheetProtectionPassword;
208 private List<Range> selectedCells;
209 private bool? freezeSplitPanes;
210 private float? paneSplitLeftWidth;
211 private float? paneSplitTopHeight;
212 private Address? paneSplitTopLeftCell;
213 private Address? paneSplitAddress;
214 private WorksheetPane? activePane;
215 private int sheetID;
216 private SheetViewType viewType;
217 private Dictionary<SheetViewType, int> zoomFactor;
218 #endregion
219
220 #region properties
225 {
226 get { return autoFilterRange; }
227 }
228
233 public IReadOnlyDictionary<string, Cell> Cells
234 {
235 get { return cellsStringView; }
236 }
237
242 public IEnumerable<Cell> CellValues
243 {
244 get { return cells.Values; }
245 }
246
250 public Dictionary<int, Column> Columns
251 {
252 get { return columns; }
253 }
254
259
265 {
266 get { return defaultColumnWidth; }
267 set
268 {
269 if (value < MinColumnWidth || value > MaxColumnWidth)
270 {
271 throw new RangeException("The passed default column width is out of range (" + MinColumnWidth + " to " + MaxColumnWidth + ")");
272 }
273 defaultColumnWidth = value;
274 }
275 }
276
281 public float DefaultRowHeight
282 {
283 get { return defaultRowHeight; }
284 set
285 {
286 if (value < MinRowHeight || value > MaxRowHeight)
287 {
288 throw new RangeException("The passed default row height is out of range (" + MinRowHeight + " to " + MaxRowHeight + ")");
289 }
290 defaultRowHeight = value;
291 }
292 }
293
298 public Dictionary<int, bool> HiddenRows
299 {
300 get { return hiddenRows; }
301 }
302
306 public Dictionary<int, float> RowHeights
307 {
308 get { return rowHeights; }
309 }
310
314 public Dictionary<string, Range> MergedCells
315 {
316 get { return mergedCells; }
317 }
318
322 public List<Range> SelectedCells
323 {
324 get { return selectedCells; }
325 }
326
330 public int SheetID
331 {
332 get => sheetID;
333 set
334 {
335 if (value < 1)
336 {
337 throw new FormatException("The ID " + value + " is invalid. Worksheet IDs must be >0");
338 }
339 sheetID = value;
340 }
341 }
342
346 public string SheetName
347 {
348 get { return sheetName; }
349 set { SetSheetName(value); }
350 }
351
357 {
358 get { return sheetProtectionPassword; }
359 internal set { sheetProtectionPassword = value; }
360 }
361
365 public List<SheetProtectionValue> SheetProtectionValues
366 {
367 get { return sheetProtectionValues; }
368 }
369
373 public bool UseSheetProtection { get; set; }
374
379 {
380 get { return workbookReference; }
381 set
382 {
383 workbookReference = value;
384 if (value != null)
385 {
386 workbookReference.ValidateWorksheets();
387 }
388 }
389 }
390
396 public bool Hidden
397 {
398 get { return hidden; }
399 set
400 {
401 hidden = value;
402 if (value && workbookReference != null)
403 {
404 workbookReference.ValidateWorksheets();
405 }
406 }
407 }
408
417 public float? PaneSplitTopHeight
418 {
419 get { return paneSplitTopHeight; }
420 }
421
430 public float? PaneSplitLeftWidth
431 {
432 get { return paneSplitLeftWidth; }
433 }
434
439 public bool? FreezeSplitPanes
440 {
441 get { return freezeSplitPanes; }
442 }
443
450 {
451 get { return paneSplitTopLeftCell; }
452 }
453
462 {
463 get { return paneSplitAddress; }
464 }
465
466
472 {
473 get { return activePane; }
474 }
475
480 {
481 get { return activeStyle; }
482 }
483
487 public bool ShowGridLines { get; set; }
488
492 public bool ShowRowColumnHeaders { get; set; }
493
497 public bool ShowRuler { get; set; }
498
503 {
504 get
505 {
506 return viewType;
507 }
508 set
509 {
510 viewType = value;
511 SetZoomFactor(value, 100);
512 }
513 }
514
520 public int ZoomFactor
521 {
522 set
523 {
524 SetZoomFactor(viewType, value);
525 }
526 get
527 {
528 return zoomFactor[viewType];
529 }
530 }
531
535 public Dictionary<SheetViewType, int> ZoomFactors
536 {
537 get
538 {
539 return zoomFactor;
540 }
541 }
542
546 internal FeatureSet Features { get; } = new FeatureSet() { };
547
548 #endregion
549
550
551 #region constructors
555 public Worksheet()
556 {
557 CurrentCellDirection = CellDirection.ColumnToColumn;
558 cells = new Dictionary<CellKey, Cell>(1000); // Let's assume a default of 1000 cells per worksheet, which is a good starting point for most use cases. This can be adjusted if needed, but it will save some resizing operations on the dictionary in the average case
559 cellsStringView = new StringKeyedCellView(cells);
560 currentRowNumber = 0;
561 currentColumnNumber = 0;
562 defaultColumnWidth = DefaultWorksheetColumnWidth;
563 defaultRowHeight = DefaultWorksheetRowHeight;
564 rowHeights = new Dictionary<int, float>();
565 mergedCells = new Dictionary<string, Range>();
566 selectedCells = new List<Range>();
567 sheetProtectionValues = new List<SheetProtectionValue>();
568 hiddenRows = new Dictionary<int, bool>();
569 columns = new Dictionary<int, Column>();
570 activeStyle = null;
571 workbookReference = null;
572 viewType = SheetViewType.Normal;
573 zoomFactor = new Dictionary<SheetViewType, int>
574 {
575 { viewType, 100 }
576 };
577 ShowGridLines = true;
579 ShowRuler = true;
580 sheetProtectionPassword = new LegacyPassword(LegacyPassword.PasswordType.WorksheetProtection);
581 }
582
587 public Worksheet(string name)
588 : this()
589 {
590 SetSheetName(name);
591 }
592
599 public Worksheet(string name, int id, Workbook reference)
600 : this()
601 {
602 SetSheetName(name);
603 SheetID = id;
604 workbookReference = reference;
605 }
606
607 #endregion
608
609 #region methods_AddNextCell
610
619 public void AddNextCell(object value)
620 {
621 AddNextCell(CastValue(value, currentColumnNumber, currentRowNumber), true, null);
622 }
623
624
635 public void AddNextCell(object value, Style style)
636 {
637 AddNextCell(CastValue(value, currentColumnNumber, currentRowNumber), true, style);
638 }
639
640
650 private void AddNextCell(Cell cell, bool incremental, Style style)
651 {
652 // date and time styles are already defined by the passed cell object
653 if (style != null || (activeStyle != null && useActiveStyle))
654 {
655 if (cell.CellStyle == null && useActiveStyle)
656 {
657 cell.SetStyle(activeStyle);
658 }
659 else if (cell.CellStyle == null && style != null)
660 {
661 cell.SetStyle(style);
662 }
663 else if (cell.CellStyle != null && useActiveStyle)
664 {
665 Style mixedStyle = (Style)cell.CellStyle.Copy();
666 mixedStyle.Append(activeStyle);
667 cell.SetStyle(mixedStyle);
668 }
669 else if (cell.CellStyle != null && style != null)
670 {
671 Style mixedStyle = (Style)cell.CellStyle.Copy();
672 mixedStyle.Append(style);
673 cell.SetStyle(mixedStyle);
674 }
675 }
676 CellKey cellKey = new CellKey(cell.ColumnNumber, cell.RowNumber);
677 if (cells.TryGetValue(cellKey, out Cell previousCell))
678 {
679 previousCell.UnbindFeatures();
680 }
681 cells[cellKey] = cell;
682 cell.BindFeatures(Features);
683 if (incremental)
684 {
685 if (CurrentCellDirection == CellDirection.ColumnToColumn)
686 {
687 currentColumnNumber++;
688 }
689 else if (CurrentCellDirection == CellDirection.RowToRow)
690 {
691 currentRowNumber++;
692 }
693 else
694 {
695 // disabled / no-op
696 }
697 }
698 else
699 {
700 if (CurrentCellDirection == CellDirection.ColumnToColumn)
701 {
702 currentColumnNumber = cell.ColumnNumber + 1;
703 currentRowNumber = cell.RowNumber;
704 }
705 else if (CurrentCellDirection == CellDirection.RowToRow)
706 {
707 currentColumnNumber = cell.ColumnNumber;
708 currentRowNumber = cell.RowNumber + 1;
709 }
710 else
711 {
712 // disabled / no-op
713 }
714 }
715 }
716
724 private static Cell CastValue(object value, int column, int row)
725 {
726 Cell c;
727 if (value != null && value.GetType() == typeof(Cell))
728 {
729 c = (Cell)value;
730 c.CellAddress2 = new Address(column, row);
731 }
732 else
733 {
734 c = new Cell(value, Cell.CellType.Default, column, row);
735 }
736 return c;
737 }
738
739
740 #endregion
741
742 #region methods_AddCell
743
754 public void AddCell(object value, int columnNumber, int rowNumber)
755 {
756 AddNextCell(CastValue(value, columnNumber, rowNumber), false, null);
757 }
758
771 public void AddCell(object value, int columnNumber, int rowNumber, Style style)
772 {
773 AddNextCell(CastValue(value, columnNumber, rowNumber), false, style);
774 }
775
776
787 public void AddCell(object value, string address)
788 {
789 int column;
790 int row;
791 Cell.ResolveCellCoordinate(address, out column, out row);
792 AddCell(value, column, row);
793 }
794
807 public void AddCell(object value, string address, Style style)
808 {
809 int column;
810 int row;
811 Cell.ResolveCellCoordinate(address, out column, out row);
812 AddCell(value, column, row, style);
813 }
814
815 #endregion
816
817 #region methods_AddCellFormula
818
826 public void AddCellFormula(string formula, string address)
827 {
828 int column;
829 int row;
830 Cell.ResolveCellCoordinate(address, out column, out row);
831 Cell c = new Cell(formula, Cell.CellType.Formula, column, row);
832 AddNextCell(c, false, null);
833 }
834
844 public void AddCellFormula(string formula, string address, Style style)
845 {
846 int column;
847 int row;
848 Cell.ResolveCellCoordinate(address, out column, out row);
849 Cell c = new Cell(formula, Cell.CellType.Formula, column, row);
850 AddNextCell(c, false, style);
851 }
852
860 public void AddCellFormula(string formula, int columnNumber, int rowNumber)
861 {
862 Cell c = new Cell(formula, Cell.CellType.Formula, columnNumber, rowNumber);
863 AddNextCell(c, false, null);
864 }
865
874 public void AddCellFormula(string formula, int columnNumber, int rowNumber, Style style)
875 {
876 Cell c = new Cell(formula, Cell.CellType.Formula, columnNumber, rowNumber);
877 AddNextCell(c, false, style);
878 }
879
886 public void AddNextCellFormula(string formula)
887 {
888 Cell c = new Cell(formula, Cell.CellType.Formula, currentColumnNumber, currentRowNumber);
889 AddNextCell(c, true, null);
890 }
891
899 public void AddNextCellFormula(string formula, Style style)
900 {
901 Cell c = new Cell(formula, Cell.CellType.Formula, currentColumnNumber, currentRowNumber);
902 AddNextCell(c, true, style);
903 }
904
905 #endregion
906
907 #region methods_AddCellReference
908
923 public IReadOnlyList<Address> AddCellReference(DefinedName definedName, int columnNumber, int rowNumber, object cachedValue = null)
924 {
925 if (definedName == null)
926 {
927 throw new WorksheetException("The defined name to set as cell reference must not be null.");
928 }
929 Cell c = new Cell(definedName.Name, Cell.CellType.Formula, columnNumber, rowNumber);
930 Range? arrayRange = c.SetReference(definedName, cachedValue);
931 if (arrayRange.HasValue)
932 {
933 c.Formula.FormulaRange = arrayRange.Value.ToString();
934 }
935 AddNextCell(c, false, null);
936 List<Address> list = new List<Address>();
937 list.Add(new Address(columnNumber, rowNumber));
938 if (arrayRange.HasValue)
939 {
940 IReadOnlyList<Address> addedCells = AddDefinedNameArrayCells(c, arrayRange.Value, null);
941 list.AddRange(addedCells);
942 }
943 return list;
944 }
945
961 public IReadOnlyList<Address> AddCellReference(DefinedName definedName, int columnNumber, int rowNumber, Style style, object cachedValue = null)
962 {
963 if (definedName == null)
964 {
965 throw new WorksheetException("The defined name to set as cell reference must not be null.");
966 }
967 Cell c = new Cell(definedName.Name, Cell.CellType.Formula, columnNumber, rowNumber);
968 Range? arrayRange = c.SetReference(definedName, cachedValue);
969 if (arrayRange.HasValue)
970 {
971 c.Formula.FormulaRange = arrayRange.Value.ToString();
972 }
973 AddNextCell(c, false, style);
974 List<Address> list = new List<Address>();
975 list.Add(new Address(columnNumber, rowNumber));
976 if (arrayRange.HasValue)
977 {
978 IReadOnlyList<Address> addedCells = AddDefinedNameArrayCells(c, arrayRange.Value, style);
979 list.AddRange(addedCells);
980 }
981 return list;
982 }
983
997 public IReadOnlyList<Address> AddCellReference(DefinedName definedName, string address, object cachedValue = null)
998 {
999 int column;
1000 int row;
1001 Cell.ResolveCellCoordinate(address, out column, out row);
1002 return AddCellReference(definedName, column, row, cachedValue);
1003 }
1004
1020 public IReadOnlyList<Address> AddCellReference(DefinedName definedName, string address, Style style, object cachedValue = null)
1021 {
1022 int column;
1023 int row;
1024 Cell.ResolveCellCoordinate(address, out column, out row);
1025 return AddCellReference(definedName, column, row, style, cachedValue);
1026 }
1027
1035 internal IReadOnlyList<Address> AddDefinedNameArrayCells(Cell masterCell, Range arrayRange, Style style)
1036 {
1037 IReadOnlyList<Address> addresses = arrayRange.ResolveEnclosedAddresses();
1038 List<Address> addedAddresses = new List<Address>();
1039 foreach (Address address in addresses)
1040 {
1041 if (address.Row == masterCell.RowNumber && address.Column == masterCell.ColumnNumber)
1042 {
1043 continue; // Skip master cell
1044 }
1045 Cell arrayRefCell = new Cell(null, Cell.CellType.Formula);
1046 arrayRefCell.Formula.MasterCellAddress = masterCell.CellAddress;
1047 arrayRefCell.Formula.FormulaRange = masterCell.Formula.FormulaRange;
1048 arrayRefCell.Formula.Type = FormulaData.FormulaType.Array;
1049 AddCell(arrayRefCell, address.Column, address.Row, style);
1050 addedAddresses.Add(address);
1051 }
1052 return addedAddresses;
1053 }
1054
1055 #endregion
1056
1057 #region methods_AddCellRange
1058
1069 public void AddCellRange(IReadOnlyList<object> values, Address startAddress, Address endAddress)
1070 {
1071 AddCellRangeInternal(values, startAddress, endAddress, null);
1072 }
1073
1086 public void AddCellRange(IReadOnlyList<object> values, Address startAddress, Address endAddress, Style style)
1087 {
1088 AddCellRangeInternal(values, startAddress, endAddress, style);
1089 }
1090
1101 public void AddCellRange(IReadOnlyList<object> values, string cellRange)
1102 {
1103 Range range = Cell.ResolveCellRange(cellRange);
1104 AddCellRangeInternal(values, range.StartAddress, range.EndAddress, null);
1105 }
1106
1119 public void AddCellRange(IReadOnlyList<object> values, string cellRange, Style style)
1120 {
1121 Range range = Cell.ResolveCellRange(cellRange);
1122 AddCellRangeInternal(values, range.StartAddress, range.EndAddress, style);
1123 }
1124
1134 public void AddCellRange(IReadOnlyList<object> values, Range cellRange)
1135 {
1136 AddCellRangeInternal(values, cellRange.StartAddress, cellRange.EndAddress, null);
1137 }
1138
1150 public void AddCellRange(IReadOnlyList<object> values, Range cellRange, Style style)
1151 {
1152 AddCellRangeInternal(values, cellRange.StartAddress, cellRange.EndAddress, style);
1153 }
1154
1166 private void AddCellRangeInternal<T>(IReadOnlyList<T> values, Address startAddress, Address endAddress, Style style)
1167 {
1168 if (values == null)
1169 {
1170 throw new RangeException("The passed value list cannot be null");
1171 }
1172 List<Address> addresses = Cell.GetCellRange(startAddress, endAddress) as List<Address>;
1173 if (values.Count != addresses.Count)
1174 {
1175 throw new RangeException("The number of passed values (" + values.Count + ") differs from the number of cells within the range (" + addresses.Count + ")");
1176 }
1177 List<Cell> list = Cell.ConvertArray(values) as List<Cell>;
1178 int len = values.Count;
1179 for (int i = 0; i < len; i++)
1180 {
1181 list[i].RowNumber = addresses[i].Row;
1182 list[i].ColumnNumber = addresses[i].Column;
1183 AddNextCell(list[i], false, style);
1184 }
1185 }
1186 #endregion
1187
1188 #region methods_RemoveCell
1196 public bool RemoveCell(int columnNumber, int rowNumber)
1197 {
1198 CellKey key = new CellKey(columnNumber, rowNumber);
1199 cells.TryGetValue(key, out Cell cell);
1200 if (cell != null)
1201 {
1202 cell.UnbindFeatures(); // Decrease counter of features (if applicable)
1203 }
1204 return cells.Remove(key);
1205 }
1206
1214 public bool RemoveCell(string address)
1215 {
1216 int row;
1217 int column;
1218 Cell.ResolveCellCoordinate(address, out column, out row);
1219 return RemoveCell(column, row);
1220 }
1221 #endregion
1222
1223 #region methods_setStyle
1224
1232 public void SetStyle(Range cellRange, Style style)
1233 {
1234 IReadOnlyList<Address> addresses = cellRange.ResolveEnclosedAddresses();
1235 foreach (Address address in addresses)
1236 {
1237 if (cells.TryGetValue(new CellKey(address.Column, address.Row), out Cell existing))
1238 {
1239 if (style == null)
1240 {
1241 existing.RemoveStyle();
1242 }
1243 else
1244 {
1245 existing.SetStyle(style);
1246 }
1247 }
1248 else
1249 {
1250 if (style != null)
1251 {
1252 AddCell(null, address.Column, address.Row, style);
1253 }
1254 }
1255 }
1256 }
1257
1266 public void SetStyle(Address startAddress, Address endAddress, Style style)
1267 {
1268 SetStyle(new Range(startAddress, endAddress), style);
1269 }
1270
1278 public void SetStyle(Address address, Style style)
1279 {
1280 SetStyle(address, address, style);
1281 }
1282
1291 public void SetStyle(string addressExpression, Style style)
1292 {
1293 Cell.AddressScope scope = Cell.GetAddressScope(addressExpression);
1294 if (scope == Cell.AddressScope.SingleAddress)
1295 {
1296 Address address = new Address(addressExpression);
1297 SetStyle(address, style);
1298 }
1299 else if (scope == Cell.AddressScope.Range)
1300 {
1301 Range range = new Range(addressExpression);
1302 SetStyle(range, style);
1303 }
1304 else
1305 {
1306 throw new FormatException("The passed address'" + addressExpression + "' is neither a cell address, nor a range");
1307 }
1308 }
1309
1310 #endregion
1311
1312 #region boundaryFunctions
1320 {
1321 return GetBoundaryNumber(false, true);
1322 }
1323
1331 {
1332 return GetBoundaryDataNumber(false, true, true);
1333 }
1334
1342 {
1343 return GetBoundaryNumber(true, true);
1344 }
1345
1353 {
1354 return GetBoundaryDataNumber(true, true, true);
1355 }
1356
1365 {
1366 return GetBoundaryNumber(false, false);
1367 }
1368
1376 {
1377 return GetBoundaryDataNumber(false, false, true);
1378 }
1379
1387 public int GetLastRowNumber()
1388 {
1389 return GetBoundaryNumber(true, false);
1390 }
1391
1392
1400 {
1401 return GetBoundaryDataNumber(true, false, true);
1402 }
1403
1411
1413 {
1414 int lastRow = GetLastRowNumber();
1415 int lastColumn = GetLastColumnNumber();
1416 if (lastRow < 0 || lastColumn < 0)
1417 {
1418 return null;
1419 }
1420 return new Address(lastColumn, lastRow);
1421 }
1422
1429
1431 {
1432 int lastRow = GetLastDataRowNumber();
1433 int lastColumn = GetLastDataColumnNumber();
1434 if (lastRow < 0 || lastColumn < 0)
1435 {
1436 return null;
1437 }
1438 return new Address(lastColumn, lastRow);
1439 }
1440
1448 {
1449 int firstRow = GetFirstRowNumber();
1450 int firstColumn = GetFirstColumnNumber();
1451 if (firstRow < 0 || firstColumn < 0)
1452 {
1453 return null;
1454 }
1455 return new Address(firstColumn, firstRow);
1456 }
1457
1465 {
1466 int firstRow = GetFirstDataRowNumber();
1467 int firstColumn = GetFirstDataColumnNumber();
1468 if (firstRow < 0 || firstColumn < 0)
1469 {
1470 return null;
1471 }
1472 return new Address(firstColumn, firstRow);
1473 }
1474
1482 private int GetBoundaryDataNumber(bool row, bool min, bool ignoreEmpty)
1483 {
1484 if (cells.Count == 0)
1485 {
1486 return -1;
1487 }
1488 if (!ignoreEmpty)
1489 {
1490 if (row && min)
1491 {
1492 return cells.Values.Min(x => x.RowNumber);
1493 }
1494 else if (row)
1495 {
1496 return cells.Values.Max(x => x.RowNumber);
1497 }
1498 else if (min)
1499 {
1500 return cells.Values.Min(x => x.ColumnNumber);
1501 }
1502 else
1503 {
1504 return cells.Values.Max(x => x.ColumnNumber);
1505 }
1506 }
1507 List<Cell> nonEmptyCells = cells.Values.Where(x => x.Value != null && x.Value.ToString() != string.Empty).ToList();
1508 if (nonEmptyCells.Count == 0)
1509 {
1510 return -1;
1511 }
1512 if (row && min)
1513 {
1514 return nonEmptyCells.Min(x => x.RowNumber);
1515 }
1516 else if (row)
1517 {
1518 return nonEmptyCells.Max(x => x.RowNumber);
1519 }
1520 else if (min)
1521 {
1522 return nonEmptyCells.Min(x => x.ColumnNumber);
1523 }
1524 else
1525 {
1526 return nonEmptyCells.Max(x => x.ColumnNumber);
1527 }
1528 }
1529
1536 private int GetBoundaryNumber(bool row, bool min)
1537 {
1538 int cellBoundary = GetBoundaryDataNumber(row, min, false);
1539 if (row)
1540 {
1541 int heightBoundary = -1;
1542 if (rowHeights.Count > 0)
1543 {
1544 heightBoundary = min ? RowHeights.Min(x => x.Key) : RowHeights.Max(x => x.Key);
1545 }
1546 int hiddenBoundary = -1;
1547 if (hiddenRows.Count > 0)
1548 {
1549 hiddenBoundary = min ? HiddenRows.Min(x => x.Key) : HiddenRows.Max(x => x.Key);
1550 }
1551 return min ? GetMinRow(cellBoundary, heightBoundary, hiddenBoundary) : GetMaxRow(cellBoundary, heightBoundary, hiddenBoundary);
1552 }
1553 else
1554 {
1555 int columnDefBoundary = -1;
1556 if (columns.Count > 0)
1557 {
1558 columnDefBoundary = min ? Columns.Min(x => x.Key) : Columns.Max(x => x.Key);
1559 }
1560 if (min)
1561 {
1562 return cellBoundary >= 0 && cellBoundary < columnDefBoundary ? cellBoundary : columnDefBoundary;
1563 }
1564 else
1565 {
1566 return cellBoundary >= 0 && cellBoundary > columnDefBoundary ? cellBoundary : columnDefBoundary;
1567 }
1568 }
1569 }
1570
1578 private static int GetMaxRow(int cellBoundary, int heightBoundary, int hiddenBoundary)
1579 {
1580 int highest = -1;
1581 if (cellBoundary >= 0)
1582 {
1583 highest = cellBoundary;
1584 }
1585 if (heightBoundary >= 0 && heightBoundary > highest)
1586 {
1587 highest = heightBoundary;
1588 }
1589 if (hiddenBoundary >= 0 && hiddenBoundary > highest)
1590 {
1591 highest = hiddenBoundary;
1592 }
1593 return highest;
1594 }
1595
1603 private static int GetMinRow(int cellBoundary, int heightBoundary, int hiddenBoundary)
1604 {
1605 int lowest = int.MaxValue;
1606 if (cellBoundary >= 0)
1607 {
1608 lowest = cellBoundary;
1609 }
1610 if (heightBoundary >= 0 && heightBoundary < lowest)
1611 {
1612 lowest = heightBoundary;
1613 }
1614 if (hiddenBoundary >= 0 && hiddenBoundary < lowest)
1615 {
1616 lowest = hiddenBoundary;
1617 }
1618 return lowest == int.MaxValue ? -1 : lowest;
1619 }
1620 #endregion
1621
1622 #region Insert-Search-Replace
1623
1632 public void InsertRow(int rowNumber, int numberOfNewRows)
1633 {
1634 // All cells below the first row must receive a new address (row + count);
1635 var upperRow = this.GetRow(rowNumber);
1636
1637 // Identify all cells below the insertion point to adjust their addresses
1638 var cellsToChange = cells.Values.Where(c => c.CellAddress2.Row > rowNumber).ToList();
1639
1640 // Make a copy of the cells to be moved and then delete the original cells;
1641 List<Cell> newCells = new List<Cell>();
1642 foreach (Cell cell in cellsToChange)
1643 {
1644 int row = cell.CellAddress2.Row;
1645 int col = cell.CellAddress2.Column;
1646 Address newAddress = new Address(col, row + numberOfNewRows);
1647 Cell newCell = new Cell(cell.Value, cell.DataType, newAddress);
1648 if (cell.CellStyle != null)
1649 {
1650 newCell.SetStyle(cell.CellStyle);
1651 }
1652 newCells.Add(newCell);
1653 cells.Remove(new CellKey(col, row));
1654 }
1655
1656 // Fill the gap with new cells, using the same style as the first row.
1657 foreach (Cell cell in upperRow)
1658 {
1659 for (int i = 0; i < numberOfNewRows; i++)
1660 {
1661 Address newAddress = new Address(cell.CellAddress2.Column, cell.CellAddress2.Row + 1 + i);
1662 Cell newCell = new Cell(null, Cell.CellType.Empty, newAddress);
1663 if (cell.CellStyle != null)
1664 {
1665 newCell.SetStyle(cell.CellStyle);
1666 }
1667 cells[new CellKey(newAddress.Column, newAddress.Row)] = newCell;
1668 }
1669 }
1670
1671 // Re-add the displaced cells with their new addresses.
1672 foreach (Cell newCell in newCells)
1673 {
1674 cells[new CellKey(newCell.ColumnNumber, newCell.RowNumber)] = newCell;
1675 }
1676 }
1677
1686 public void InsertColumn(int columnNumber, int numberOfNewColumns)
1687 {
1688 var leftColumn = this.GetColumn(columnNumber);
1689 var cellsToChange = cells.Values.Where(c => c.CellAddress2.Column > columnNumber).ToList();
1690
1691 List<Cell> newCells = new List<Cell>();
1692 foreach (Cell cell in cellsToChange)
1693 {
1694 int row = cell.CellAddress2.Row;
1695 int col = cell.CellAddress2.Column;
1696 Address newAddress = new Address(col + numberOfNewColumns, row);
1697 Cell newCell = new Cell(cell.Value, cell.DataType, newAddress);
1698 if (cell.CellStyle != null)
1699 {
1700 newCell.SetStyle(cell.CellStyle);
1701 }
1702 newCells.Add(newCell);
1703 cells.Remove(new CellKey(col, row));
1704 }
1705
1706 // Fill the gap with new cells, using the same style as the left column.
1707 foreach (Cell cell in leftColumn)
1708 {
1709 for (int i = 0; i < numberOfNewColumns; i++)
1710 {
1711 Address newAddress = new Address(cell.CellAddress2.Column + 1 + i, cell.CellAddress2.Row);
1712 Cell newCell = new Cell(null, Cell.CellType.Empty, newAddress);
1713 if (cell.CellStyle != null)
1714 {
1715 newCell.SetStyle(cell.CellStyle);
1716 }
1717 cells[new CellKey(newAddress.Column, newAddress.Row)] = newCell;
1718 }
1719 }
1720
1721 // Re-add the displaced cells with their new addresses.
1722 foreach (Cell newCell in newCells)
1723 {
1724 cells[new CellKey(newCell.ColumnNumber, newCell.RowNumber)] = newCell;
1725 }
1726 }
1727
1733 public Cell FirstCellByValue(object searchValue)
1734 {
1735 return cells.Values.FirstOrDefault(c => Equals(c.Value, searchValue));
1736 }
1737
1744 public Cell FirstOrDefaultCell(Func<Cell, bool> predicate)
1745 {
1746 return cells.Values.FirstOrDefault(c => c != null && (c.Value == null || predicate(c)));
1747 }
1748
1754 public List<Cell> CellsByValue(object searchValue)
1755 {
1756 return cells.Values.Where(c => Equals(c.Value, searchValue)).ToList();
1757 }
1758
1765 public int ReplaceCellValue(object oldValue, object newValue)
1766 {
1767 int count = 0;
1768 List<Cell> foundCells = this.CellsByValue(oldValue);
1769 foreach (var cell in foundCells)
1770 {
1771 cell.Value = newValue;
1772 count++;
1773 }
1774 return count;
1775 }
1776 #endregion
1777
1778 #region common_methods
1779
1786 {
1787 if (!sheetProtectionValues.Contains(typeOfProtection))
1788 {
1789 if (typeOfProtection == SheetProtectionValue.SelectLockedCells && !sheetProtectionValues.Contains(SheetProtectionValue.SelectUnlockedCells))
1790 {
1791 sheetProtectionValues.Add(SheetProtectionValue.SelectUnlockedCells);
1792 }
1793 sheetProtectionValues.Add(typeOfProtection);
1794 UseSheetProtection = true;
1795 }
1796 }
1797
1803 public void AddHiddenColumn(int columnNumber)
1804 {
1805 SetColumnHiddenState(columnNumber, true);
1806 }
1807
1813 public void AddHiddenColumn(string columnAddress)
1814 {
1815 int columnNumber = Cell.ResolveColumn(columnAddress);
1816 SetColumnHiddenState(columnNumber, true);
1817 }
1818
1824 public void AddHiddenRow(int rowNumber)
1825 {
1826 SetRowHiddenState(rowNumber, true);
1827 }
1828
1832 public void ClearActiveStyle()
1833 {
1834 useActiveStyle = false;
1835 activeStyle = null;
1836 }
1837
1844 public Cell GetCell(Address address)
1845 {
1846 if (!cells.TryGetValue(new CellKey(address.Column, address.Row), out Cell cell))
1847 {
1848 throw new WorksheetException("The cell with the address " + address.GetAddress() + " does not exist in this worksheet");
1849 }
1850 return cell;
1851 }
1852
1860 public Cell GetCell(int columnNumber, int rowNumber)
1861 {
1862 return GetCell(new Address(columnNumber, rowNumber));
1863 }
1864
1872 public bool HasCell(Address address)
1873 {
1874 return cells.ContainsKey(new CellKey(address.Column, address.Row));
1875 }
1876
1886 public bool HasCell(int columnNumber, int rowNumber)
1887 {
1888 return HasCell(new Address(columnNumber, rowNumber));
1889 }
1890
1896 public void ResetColumn(int columnNumber)
1897 {
1898 if (columns.TryGetValue(columnNumber, out var value) && !value.HasAutoFilter) // AutoFilters cannot have gaps
1899 {
1900 columns.Remove(columnNumber);
1901 }
1902 else if (columns.TryGetValue(columnNumber, out var value2))
1903 {
1904 value2.IsHidden = false;
1905 value2.Width = DefaultWorksheetColumnWidth;
1906 }
1907 }
1908
1914 public IReadOnlyList<Cell> GetRow(int rowNumber)
1915 {
1916 List<Cell> list = new List<Cell>();
1917 foreach (Cell cell in cells.Values)
1918 {
1919 if (cell.RowNumber == rowNumber)
1920 {
1921 list.Add(cell);
1922 }
1923 }
1924 list.Sort((c1, c2) => (c1.ColumnNumber.CompareTo(c2.ColumnNumber))); // Lambda sort
1925 return list;
1926 }
1927
1934 public IReadOnlyList<Cell> GetColumn(string columnAddress)
1935 {
1936 int column = Cell.ResolveColumn(columnAddress);
1937 return GetColumn(column);
1938 }
1939
1945 public IReadOnlyList<Cell> GetColumn(int columnNumber)
1946 {
1947 List<Cell> list = new List<Cell>();
1948 foreach (Cell cell in cells.Values)
1949 {
1950 if (cell.ColumnNumber == columnNumber)
1951 {
1952 list.Add(cell);
1953 }
1954 }
1955 list.Sort((c1, c2) => (c1.RowNumber.CompareTo(c2.RowNumber))); // Lambda sort
1956 return list;
1957 }
1958
1964 {
1965 return currentColumnNumber;
1966 }
1967
1973 {
1974 return currentRowNumber;
1975 }
1976
1980 public void GoToNextColumn()
1981 {
1982 currentColumnNumber++;
1983 currentRowNumber = 0;
1984 Cell.ValidateColumnNumber(currentColumnNumber);
1985 }
1986
1993 public void GoToNextColumn(int numberOfColumns, bool keepRowPosition = false)
1994 {
1995 currentColumnNumber += numberOfColumns;
1996 if (!keepRowPosition)
1997 {
1998 currentRowNumber = 0;
1999 }
2000 Cell.ValidateColumnNumber(currentColumnNumber);
2001 }
2002
2006 public void GoToNextRow()
2007 {
2008 currentRowNumber++;
2009 currentColumnNumber = 0;
2010 Cell.ValidateRowNumber(currentRowNumber);
2011 }
2012
2019 public void GoToNextRow(int numberOfRows, bool keepColumnPosition = false)
2020 {
2021 currentRowNumber += numberOfRows;
2022 if (!keepColumnPosition)
2023 {
2024 currentColumnNumber = 0;
2025 }
2026 Cell.ValidateRowNumber(currentRowNumber);
2027 }
2028
2035 public string MergeCells(Range cellRange)
2036 {
2037 return MergeCells(cellRange.StartAddress, cellRange.EndAddress);
2038 }
2039
2047 public string MergeCells(string cellRange)
2048 {
2049 Range range = Cell.ResolveCellRange(cellRange);
2050 return MergeCells(range.StartAddress, range.EndAddress);
2051 }
2052
2060 public string MergeCells(Address startAddress, Address endAddress)
2061 {
2062 string key = startAddress + ":" + endAddress;
2063 Range value = new Range(startAddress, endAddress);
2064 IReadOnlyList<Address> result = value.ResolveEnclosedAddresses();
2065 foreach (KeyValuePair<string, Range> item in mergedCells)
2066 {
2067 if (item.Value.ResolveEnclosedAddresses().Intersect(result).Any())
2068 {
2069 throw new RangeException("The passed range: " + value.ToString() + " contains cells that are already in the defined merge range: " + item.Key);
2070 }
2071 }
2072 mergedCells.Add(key, value);
2073 return key;
2074 }
2075
2079 internal void RecalculateAutoFilter()
2080 {
2081 if (autoFilterRange == null)
2082 { return; }
2083 int start = autoFilterRange.Value.StartAddress.Column;
2084 int end = autoFilterRange.Value.EndAddress.Column;
2085 int endRow = 0;
2086 foreach (Cell item in CellValues)
2087 {
2088 if (item.ColumnNumber < start || item.ColumnNumber > end)
2089 { continue; }
2090 if (item.RowNumber > endRow)
2091 { endRow = item.RowNumber; }
2092 }
2093 Column c;
2094 for (int i = start; i <= end; i++)
2095 {
2096 if (!columns.TryGetValue(i, out var value))
2097 {
2098 c = new Column(i)
2099 {
2100 HasAutoFilter = true
2101 };
2102 columns.Add(i, c);
2103 }
2104 else
2105 {
2106 value.HasAutoFilter = true;
2107 }
2108 }
2109 autoFilterRange = new Range(start, 0, end, endRow);
2110 }
2111
2115 internal void RecalculateColumns()
2116 {
2117 List<int> columnsToDelete = new List<int>();
2118 foreach (KeyValuePair<int, Column> col in columns)
2119 {
2120 if (!col.Value.HasAutoFilter && !col.Value.IsHidden && Comparators.CompareDimensions(col.Value.Width, DefaultWorksheetColumnWidth) == 0 && col.Value.DefaultColumnStyle == null)
2121 {
2122 columnsToDelete.Add(col.Key);
2123 }
2124 }
2125 foreach (int index in columnsToDelete)
2126 {
2127 columns.Remove(index);
2128 }
2129 }
2130
2136 internal void ResolveMergedCells()
2137 {
2138 Style mergeStyle = BasicStyles.MergeCellStyle;
2139 Cell cell;
2140 foreach (KeyValuePair<string, Range> range in MergedCells)
2141 {
2142 int pos = 0;
2143 List<Address> addresses = Cell.GetCellRange(range.Value.StartAddress, range.Value.EndAddress) as List<Address>;
2144 foreach (Address address in addresses)
2145 {
2146 if (!cells.TryGetValue(new CellKey(address.Column, address.Row), out cell))
2147 {
2148 cell = new Cell
2149 {
2150 DataType = Cell.CellType.Empty,
2151 RowNumber = address.Row,
2152 ColumnNumber = address.Column
2153 };
2154 AddCell(cell, cell.ColumnNumber, cell.RowNumber);
2155 }
2156 if (pos != 0)
2157 {
2158 cell.DataType = Cell.CellType.Empty;
2159 if (cell.CellStyle == null)
2160 {
2161 cell.SetStyle(mergeStyle);
2162 }
2163 else
2164 {
2165 Style mixedMergeStyle = cell.CellStyle;
2166 // TODO: There should be a better possibility to identify particular style elements that deviates
2167 mixedMergeStyle.CurrentCellXf.ForceApplyAlignment = mergeStyle.CurrentCellXf.ForceApplyAlignment;
2168 cell.SetStyle(mixedMergeStyle);
2169 }
2170 }
2171 pos++;
2172 }
2173 }
2174 }
2175
2179 public void RemoveAutoFilter()
2180 {
2181 autoFilterRange = null;
2182 }
2183
2189 public void RemoveHiddenColumn(int columnNumber)
2190 {
2191 SetColumnHiddenState(columnNumber, false);
2192 }
2193
2199 public void RemoveHiddenColumn(string columnAddress)
2200 {
2201 int columnNumber = Cell.ResolveColumn(columnAddress);
2202 SetColumnHiddenState(columnNumber, false);
2203 }
2204
2210 public void RemoveHiddenRow(int rowNumber)
2211 {
2212 SetRowHiddenState(rowNumber, false);
2213 }
2214
2220 public void RemoveMergedCells(string range)
2221 {
2222 range = ParserUtils.ToUpper(range);
2223 if (range == null || !mergedCells.ContainsKey(range))
2224 {
2225 throw new RangeException("The cell range " + range + " was not found in the list of merged cell ranges");
2226 }
2227
2228 List<Address> addresses = Cell.GetCellRange(range) as List<Address>;
2229 foreach (Address address in addresses)
2230 {
2231 if (cells.TryGetValue(new CellKey(address.Column, address.Row), out Cell cell))
2232 {
2233 if (BasicStyles.MergeCellStyle.Equals(cell.CellStyle))
2234 {
2235 cell.RemoveStyle();
2236 }
2237 cell.ResolveCellType(); // resets the type
2238 }
2239 }
2240 mergedCells.Remove(range);
2241 }
2242
2247 public void RemoveRowHeight(int rowNumber)
2248 {
2249 if (rowHeights.ContainsKey(rowNumber))
2250 {
2251 rowHeights.Remove(rowNumber);
2252 }
2253 }
2254
2260 {
2261 if (sheetProtectionValues.Contains(value))
2262 {
2263 sheetProtectionValues.Remove(value);
2264 }
2265 }
2266
2271 public void SetActiveStyle(Style style)
2272 {
2273 if (style == null)
2274 {
2275 useActiveStyle = false;
2276 }
2277 else
2278 {
2279 useActiveStyle = true;
2280 }
2281 activeStyle = style;
2282 }
2283
2290 public void SetAutoFilter(int startColumn, int endColumn)
2291 {
2292 string start = Cell.ResolveCellAddress(startColumn, 0);
2293 string end = Cell.ResolveCellAddress(endColumn, 0);
2294 if (endColumn < startColumn)
2295 {
2296 SetAutoFilter(end + ":" + start);
2297 }
2298 else
2299 {
2300 SetAutoFilter(start + ":" + end);
2301 }
2302 }
2303
2310 public void SetAutoFilter(string range)
2311 {
2312 autoFilterRange = Cell.ResolveCellRange(range);
2313 RecalculateAutoFilter();
2314 RecalculateColumns();
2315 }
2316
2323 private void SetColumnHiddenState(int columnNumber, bool state)
2324 {
2325 Cell.ValidateColumnNumber(columnNumber);
2326 if (columns.TryGetValue(columnNumber, out var value))
2327 {
2328 value.IsHidden = state;
2329 }
2330 else if (state)
2331 {
2332 Column c = new Column(columnNumber)
2333 {
2334 IsHidden = true
2335 };
2336 columns.Add(columnNumber, c);
2337 }
2338 if (!columns[columnNumber].IsHidden && Comparators.CompareDimensions(columns[columnNumber].Width, DefaultWorksheetColumnWidth) == 0 && !columns[columnNumber].HasAutoFilter)
2339 {
2340 columns.Remove(columnNumber);
2341 }
2342 }
2343
2350 public void SetColumnWidth(string columnAddress, float width)
2351 {
2352 int columnNumber = Cell.ResolveColumn(columnAddress);
2353 SetColumnWidth(columnNumber, width);
2354 }
2355
2362 public void SetColumnWidth(int columnNumber, float width)
2363 {
2364 Cell.ValidateColumnNumber(columnNumber);
2365 if (width < MinColumnWidth || width > MaxColumnWidth)
2366 {
2367 throw new RangeException("The column width (" + width + ") is out of range. Range is from " + MinColumnWidth + " to " + MaxColumnWidth + " (chars).");
2368 }
2369 if (columns.TryGetValue(columnNumber, out var value))
2370 {
2371 value.Width = width;
2372 }
2373 else
2374 {
2375 Column c = new Column(columnNumber)
2376 {
2377 Width = width
2378 };
2379 columns.Add(columnNumber, c);
2380 }
2381 }
2382
2390 public Style SetColumnDefaultStyle(string columnAddress, Style style)
2391 {
2392 int columnNumber = Cell.ResolveColumn(columnAddress);
2393 return SetColumnDefaultStyle(columnNumber, style);
2394 }
2395
2402 public Style SetColumnDefaultStyle(int columnNumber, Style style)
2403 {
2404 Cell.ValidateColumnNumber(columnNumber);
2405 if (this.columns.TryGetValue(columnNumber, out var value))
2406 {
2407 return value.SetDefaultColumnStyle(style);
2408 }
2409 else
2410 {
2411 Column c = new Column(columnNumber);
2412 Style returnStyle = c.SetDefaultColumnStyle(style);
2413 this.columns.Add(columnNumber, c);
2414 return returnStyle;
2415 }
2416 }
2417
2424 public void SetCurrentCellAddress(int columnNumber, int rowNumber)
2425 {
2426 SetCurrentColumnNumber(columnNumber);
2427 SetCurrentRowNumber(rowNumber);
2428 }
2429
2436 public void SetCurrentCellAddress(string address)
2437 {
2438 int row;
2439 int column;
2440 Cell.ResolveCellCoordinate(address, out column, out row);
2441 SetCurrentCellAddress(column, row);
2442 }
2443
2449 public void SetCurrentColumnNumber(int columnNumber)
2450 {
2451 Cell.ValidateColumnNumber(columnNumber);
2452 currentColumnNumber = columnNumber;
2453 }
2454
2460 public void SetCurrentRowNumber(int rowNumber)
2461 {
2462 Cell.ValidateRowNumber(rowNumber);
2463 currentRowNumber = rowNumber;
2464 }
2465
2470 public void AddSelectedCells(Range range)
2471 {
2472 selectedCells = DataUtils.MergeRange(selectedCells, range).ToList();
2473 }
2474
2480 public void AddSelectedCells(Address startAddress, Address endAddress)
2481 {
2482 AddSelectedCells(new Range(startAddress, endAddress));
2483 }
2484
2489 public void AddSelectedCells(string rangeOrAddress)
2490 {
2491 Range? resolved = ParseRange(rangeOrAddress);
2492 if (resolved != null)
2493 {
2494 AddSelectedCells(resolved.Value);
2495 }
2496 }
2497
2502 public void AddSelectedCells(Address address)
2503 {
2504 AddSelectedCells(new Range(address, address));
2505 }
2506
2511 {
2512 selectedCells.Clear();
2513 }
2514
2520 public void RemoveSelectedCells(Range range)
2521 {
2522 selectedCells = DataUtils.SubtractRange(selectedCells, range).ToList();
2523 }
2524
2529 public void RemoveSelectedCells(String rangeOrAddress)
2530 {
2531 Range? resolved = ParseRange(rangeOrAddress);
2532 if (resolved != null)
2533 {
2534 RemoveSelectedCells(resolved.Value);
2535 }
2536 }
2537
2543 public void RemoveSelectedCells(Address startAddress, Address endAddress)
2544 {
2545 RemoveSelectedCells(new Range(startAddress, endAddress));
2546 }
2547
2552 public void RemoveSelectedCells(Address address)
2553 {
2554 RemoveSelectedCells(new Range(address, address));
2555 }
2556
2561 public void SetSheetProtectionPassword(string password)
2562 {
2563 if (string.IsNullOrEmpty(password))
2564 {
2565 sheetProtectionPassword.UnsetPassword();
2566 UseSheetProtection = false;
2567 }
2568 else
2569 {
2570 sheetProtectionPassword.SetPassword(password);
2571 UseSheetProtection = true;
2572 }
2573 }
2574
2581 public void SetRowHeight(int rowNumber, float height)
2582 {
2583 Cell.ValidateRowNumber(rowNumber);
2584 if (height < MinRowHeight || height > MaxRowHeight)
2585 {
2586 throw new RangeException("The row height (" + height + ") is out of range. Range is from " + MinRowHeight + " to " + MaxRowHeight + " (equals 546px).");
2587 }
2588 if (rowHeights.ContainsKey(rowNumber))
2589 {
2590 rowHeights[rowNumber] = height;
2591 }
2592 else
2593 {
2594 rowHeights.Add(rowNumber, height);
2595 }
2596 }
2597
2604 private void SetRowHiddenState(int rowNumber, bool state)
2605 {
2606 Cell.ValidateRowNumber(rowNumber);
2607 if (hiddenRows.ContainsKey(rowNumber))
2608 {
2609 if (state)
2610 {
2611 hiddenRows[rowNumber] = true;
2612 }
2613 else
2614 {
2615 hiddenRows.Remove(rowNumber);
2616 }
2617 }
2618 else if (state)
2619 {
2620 hiddenRows.Add(rowNumber, true);
2621 }
2622 }
2623
2629 public void SetSheetName(string name)
2630 {
2632 sheetName = name;
2633 }
2634
2641 public void SetSheetName(string name, bool sanitize)
2642 {
2643 if (sanitize)
2644 {
2645 sheetName = ""; // Empty name (temporary) to prevent conflicts during sanitizing
2646 sheetName = SanitizeWorksheetName(name, workbookReference);
2647 }
2648 else
2649 {
2650 SetSheetName(name);
2651 }
2652 }
2653
2660 public void SetHorizontalSplit(float topPaneHeight, Address topLeftCell, WorksheetPane? activePane)
2661 {
2662 SetSplit(null, topPaneHeight, topLeftCell, activePane);
2663 }
2664
2673 public void SetHorizontalSplit(int numberOfRowsFromTop, bool freeze, Address topLeftCell, WorksheetPane? activePane)
2674 {
2675 SetSplit(null, numberOfRowsFromTop, freeze, topLeftCell, activePane);
2676 }
2677
2684 public void SetVerticalSplit(float leftPaneWidth, Address topLeftCell, WorksheetPane? activePane)
2685 {
2686 SetSplit(leftPaneWidth, null, topLeftCell, activePane);
2687 }
2688
2698 public void SetVerticalSplit(int numberOfColumnsFromLeft, bool freeze, Address topLeftCell, WorksheetPane? activePane)
2699 {
2700 SetSplit(numberOfColumnsFromLeft, null, freeze, topLeftCell, activePane);
2701 }
2702
2714 public void SetSplit(int? numberOfColumnsFromLeft, int? numberOfRowsFromTop, bool freeze, Address topLeftCell, WorksheetPane? activePane)
2715 {
2716 if (freeze)
2717 {
2718 if (numberOfColumnsFromLeft != null && topLeftCell.Column < numberOfColumnsFromLeft.Value)
2719 {
2720 throw new WorksheetException("The column number " + topLeftCell.Column +
2721 " is not valid for a frozen, vertical split with the split pane column number " + numberOfColumnsFromLeft.Value);
2722 }
2723 if (numberOfRowsFromTop != null && topLeftCell.Row < numberOfRowsFromTop.Value)
2724 {
2725 throw new WorksheetException("The row number " + topLeftCell.Row +
2726 " is not valid for a frozen, horizontal split height the split pane row number " + numberOfRowsFromTop.Value);
2727 }
2728 }
2729 this.paneSplitLeftWidth = null;
2730 this.paneSplitTopHeight = null;
2731 this.freezeSplitPanes = freeze;
2732 int row = numberOfRowsFromTop != null ? numberOfRowsFromTop.Value : 0;
2733 int column = numberOfColumnsFromLeft != null ? numberOfColumnsFromLeft.Value : 0;
2734 this.paneSplitAddress = new Address(column, row);
2735 this.paneSplitTopLeftCell = topLeftCell;
2736 this.activePane = activePane;
2737 }
2738
2748 public void SetSplit(float? leftPaneWidth, float? topPaneHeight, Address topLeftCell, WorksheetPane? activePane)
2749 {
2750 this.paneSplitLeftWidth = leftPaneWidth;
2751 this.paneSplitTopHeight = topPaneHeight;
2752 this.freezeSplitPanes = null;
2753 this.paneSplitAddress = null;
2754 this.paneSplitTopLeftCell = topLeftCell;
2755 this.activePane = activePane;
2756 }
2757
2761 public void ResetSplit()
2762 {
2763 this.paneSplitLeftWidth = null;
2764 this.paneSplitTopHeight = null;
2765 this.freezeSplitPanes = null;
2766 this.paneSplitAddress = null;
2767 this.paneSplitTopLeftCell = null;
2768 this.activePane = null;
2769 }
2770
2780 public Worksheet Copy()
2781 {
2782 Worksheet copy = new Worksheet();
2783 foreach (Cell cell in this.cells.Values)
2784 {
2785 copy.AddCell(cell.Copy(), cell.ColumnNumber, cell.RowNumber);
2786 }
2787 copy.activePane = this.activePane;
2788 copy.activeStyle = this.activeStyle;
2789 if (this.autoFilterRange.HasValue)
2790 {
2791 copy.autoFilterRange = this.autoFilterRange.Value.Copy();
2792 }
2793 foreach (KeyValuePair<int, Column> column in this.columns)
2794 {
2795 copy.columns.Add(column.Key, column.Value.Copy());
2796 }
2797 copy.CurrentCellDirection = this.CurrentCellDirection;
2798 copy.currentColumnNumber = this.currentColumnNumber;
2799 copy.currentRowNumber = this.currentRowNumber;
2800 copy.defaultColumnWidth = this.defaultColumnWidth;
2801 copy.defaultRowHeight = this.defaultRowHeight;
2802 copy.freezeSplitPanes = this.freezeSplitPanes;
2803 copy.hidden = this.hidden;
2804 foreach (KeyValuePair<int, bool> row in this.hiddenRows)
2805 {
2806 copy.hiddenRows.Add(row.Key, row.Value);
2807 }
2808 foreach (KeyValuePair<string, Range> cell in this.mergedCells)
2809 {
2810 copy.mergedCells.Add(cell.Key, cell.Value.Copy());
2811 }
2812 if (this.paneSplitAddress.HasValue)
2813 {
2814 copy.paneSplitAddress = this.paneSplitAddress.Value.Copy();
2815 }
2816 copy.paneSplitLeftWidth = this.paneSplitLeftWidth;
2817 copy.paneSplitTopHeight = this.paneSplitTopHeight;
2818 if (this.paneSplitTopLeftCell.HasValue)
2819 {
2820 copy.paneSplitTopLeftCell = this.paneSplitTopLeftCell.Value.Copy();
2821 }
2822 foreach (KeyValuePair<int, float> row in this.rowHeights)
2823 {
2824 copy.rowHeights.Add(row.Key, row.Value);
2825 }
2826 foreach (Range range in selectedCells)
2827 {
2828 copy.AddSelectedCells(range);
2829 }
2830 copy.sheetProtectionPassword.CopyFrom(this.sheetProtectionPassword);
2831 foreach (SheetProtectionValue value in this.sheetProtectionValues)
2832 {
2833 copy.sheetProtectionValues.Add(value);
2834 }
2835 copy.useActiveStyle = this.useActiveStyle;
2836 copy.UseSheetProtection = this.UseSheetProtection;
2837 copy.ShowGridLines = this.ShowGridLines;
2838 copy.ShowRowColumnHeaders = this.ShowRowColumnHeaders;
2839 copy.ShowRuler = this.ShowRuler;
2840 copy.ViewType = this.ViewType;
2841 copy.zoomFactor.Clear();
2842 foreach (KeyValuePair<SheetViewType, int> zoomFactor in this.zoomFactor)
2843 {
2844 copy.SetZoomFactor(zoomFactor.Key, zoomFactor.Value);
2845 }
2846 return copy;
2847 }
2848
2856 public void SetZoomFactor(SheetViewType sheetViewType, int zoomFactor)
2857 {
2858 if (zoomFactor != AutoZoomFactor && (zoomFactor < MinZoomFactor || zoomFactor > MaxZoomFactor))
2859 {
2860 throw new WorksheetException("The zoom factor " + zoomFactor + " is not valid. Valid are values between " + MinZoomFactor + " and " + MaxZoomFactor + ", or " + AutoZoomFactor + " (automatic)");
2861 }
2862 if (this.zoomFactor.ContainsKey(sheetViewType))
2863 {
2864 this.zoomFactor[sheetViewType] = zoomFactor;
2865 }
2866 else
2867 {
2868 this.zoomFactor.Add(sheetViewType, zoomFactor);
2869 }
2870 }
2871
2872
2873
2874 #region static_methods
2882 public static string SanitizeWorksheetName(string input, Workbook workbook)
2883 {
2884 if (string.IsNullOrEmpty(input))
2885 {
2886 input = "Sheet1";
2887 }
2888 int len;
2889 if (input.Length > MaxWorksheetNameLength)
2890 {
2892 }
2893 else
2894 {
2895 len = input.Length;
2896 }
2897 StringBuilder sb = new StringBuilder(MaxWorksheetNameLength);
2898 char c;
2899 for (int i = 0; i < len; i++)
2900 {
2901 c = input[i];
2902 if (c == '[' || c == ']' || c == '*' || c == '?' || c == '\\' || c == '/')
2903 { sb.Append('_'); }
2904 else
2905 { sb.Append(c); }
2906 }
2907 return GetUnusedWorksheetName(sb.ToString(), workbook);
2908 }
2909
2915 private static Range? ParseRange(string rangeOrAddress)
2916 {
2917 if (string.IsNullOrEmpty(rangeOrAddress))
2918 {
2919 return null;
2920 }
2921 Range range;
2922 if (rangeOrAddress.Contains(":"))
2923 {
2924 range = Cell.ResolveCellRange(rangeOrAddress);
2925 }
2926 else
2927 {
2928 Address address = Cell.ResolveCellCoordinate(rangeOrAddress);
2929 range = new Range(address, address);
2930 }
2931 return range;
2932 }
2933
2943 private static string GetUnusedWorksheetName(string name, Workbook workbook)
2944 {
2945 if (workbook == null)
2946 {
2947 throw new WorksheetException("The workbook reference is null");
2948 }
2949 if (!WorksheetExists(name, workbook))
2950 { return name; }
2951 Regex regex = new Regex(@"^(.*?)(\d{1,31})$");
2952 Match match = regex.Match(name);
2953 string prefix = name;
2954 int number = 1;
2955 if (match.Groups.Count > 1)
2956 {
2957 prefix = match.Groups[1].Value;
2958 _ = int.TryParse(match.Groups[2].Value, out number);
2959 // if this failed, the start number is 0 (parsed number was >max. int32)
2960 }
2961 while (true)
2962 {
2963 string numberString = ParserUtils.ToString(number);
2964 if (numberString.Length + prefix.Length > MaxWorksheetNameLength)
2965 {
2966 int endIndex = prefix.Length - (numberString.Length + prefix.Length - MaxWorksheetNameLength);
2967 prefix = prefix.Substring(0, endIndex);
2968 }
2969 string newName = prefix + numberString;
2970 if (!WorksheetExists(newName, workbook))
2971 { return newName; }
2972 number++;
2973 }
2974 }
2975
2982 private static bool WorksheetExists(string name, Workbook workbook)
2983 {
2984 int len = workbook.Worksheets.Count;
2985 for (int i = 0; i < len; i++)
2986 {
2987 if (workbook.Worksheets[i].SheetName == name)
2988 {
2989 return true;
2990 }
2991 }
2992 return false;
2993 }
2994
2998 internal static string GetSheetProtectionName(SheetProtectionValue protection)
2999 {
3000 string output = "";
3001 switch (protection)
3002 {
3003 case SheetProtectionValue.Objects: output = "objects"; break;
3004 case SheetProtectionValue.Scenarios: output = "scenarios"; break;
3005 case SheetProtectionValue.FormatCells: output = "formatCells"; break;
3006 case SheetProtectionValue.FormatColumns: output = "formatColumns"; break;
3007 case SheetProtectionValue.FormatRows: output = "formatRows"; break;
3008 case SheetProtectionValue.InsertColumns: output = "insertColumns"; break;
3009 case SheetProtectionValue.InsertRows: output = "insertRows"; break;
3010 case SheetProtectionValue.InsertHyperlinks: output = "insertHyperlinks"; break;
3011 case SheetProtectionValue.DeleteColumns: output = "deleteColumns"; break;
3012 case SheetProtectionValue.DeleteRows: output = "deleteRows"; break;
3013 case SheetProtectionValue.SelectLockedCells: output = "selectLockedCells"; break;
3014 case SheetProtectionValue.Sort: output = "sort"; break;
3015 case SheetProtectionValue.AutoFilter: output = "autoFilter"; break;
3016 case SheetProtectionValue.PivotTables: output = "pivotTables"; break;
3017 case SheetProtectionValue.SelectUnlockedCells: output = "selectUnlockedCells"; break;
3018 }
3019 return output;
3020 }
3021
3027 internal static WorksheetPane? GetWorksheetPaneEnum(string pane)
3028 {
3029 WorksheetPane? output = null;
3030 switch (pane)
3031 {
3032 case "topLeft": output = WorksheetPane.TopLeft; break;
3033 case "topRight": output = WorksheetPane.TopRight; break;
3034 case "bottomLeft": output = WorksheetPane.BottomLeft; break;
3035 case "bottomRight": output = WorksheetPane.BottomRight; break;
3036 }
3037 return output;
3038 }
3039
3045 internal static SheetViewType GetSheetViewTypeEnum(string viewType)
3046 {
3047 SheetViewType output = SheetViewType.Normal;
3048 switch (viewType)
3049 {
3050 case "pageBreakPreview": output = SheetViewType.PageBreakPreview; break;
3051 case "pageLayout": output = SheetViewType.PageLayout; break;
3052 }
3053 return output;
3054 }
3055 #endregion
3056 #endregion
3057
3058 }
3059}
Class representing a cell of a worksheet.
Definition Cell.cs:25
static Address ResolveCellCoordinate(string address)
Gets the column and row number (zero based) of a cell by the address.
Definition Cell.cs:879
CellType
Enum defines the basic data types of a cell.
Definition Cell.cs:35
static void ValidateRowNumber(int row)
Validates the passed (zero-based) row number. An exception will be thrown if the row is invalid.
Definition Cell.cs:1082
Address CellAddress2
Gets or sets the combined cell Address as Address object.
Definition Cell.cs:123
static string ResolveCellAddress(int column, int row, AddressType type=AddressType.Default)
Gets the address of a cell by the column and row number (zero based).
Definition Cell.cs:855
static AddressScope GetAddressScope(string addressExpression)
Gets the scope of the passed address (string expression). Scope means either single cell address or r...
Definition Cell.cs:1041
Style CellStyle
Gets the assigned style of the cell.
Definition Cell.cs:137
static Range ResolveCellRange(string range)
Resolves a cell range from the format like A1:B3 or AAD556:AAD1000.
Definition Cell.cs:970
int RowNumber
Gets or sets the number of the row (zero-based).
Definition Cell.cs:191
static void ValidateColumnNumber(int column)
Validates the passed (zero-based) column number. An exception will be thrown if the column is invalid...
Definition Cell.cs:1068
static int ResolveColumn(string columnAddress)
Gets the column number from the column address (A - XFD).
Definition Cell.cs:994
CellType DataType
Gets or sets the type of the cell.
Definition Cell.cs:158
string CellAddress
Gets or sets the combined cell Address as string in the format A1 - XFD1048576. The address may conta...
Definition Cell.cs:111
AddressScope
Enum to define the scope of a passed address string (used in static context).
Definition Cell.cs:82
FormulaData Formula
Formula object in case of the cell has the DataType CellType.Formula. Default is null,...
Definition Cell.cs:242
int ColumnNumber
Gets or sets the number of the column (zero-based).
Definition Cell.cs:144
Style SetStyle(Style style, bool unmanaged=false)
Sets the style of the cell.
Definition Cell.cs:549
static IEnumerable< Address > GetCellRange(string range)
Gets a list of cell addresses from a cell range (format A1:B3 or AAD556:AAD1000).
Definition Cell.cs:765
object Value
Gets or sets the value of the cell (generic object type). When setting a value, the DataType is autom...
Definition Cell.cs:212
Class representing a column of a worksheet.
Definition Column.cs:18
Style SetDefaultColumnStyle(Style defaultColumnStyle, bool unmanaged=false)
Sets the default style of the column.
Definition Column.cs:93
Class representing a defined name within a workbook. A defined name is a descriptive text that repres...
string Name
Gets the name of the defined name as it appears in the workbook (e.g. MyRange).
Class for exceptions regarding format error incidents.
Class for exceptions regarding range incidents (e.g. out-of-range).
Class for exceptions regarding worksheet incidents.
Class representing a formula in a cell, its data, respectively.
string FormulaRange
Gets the range associated with an array, shared, or data-table formula. Can be a range or address (st...
FormulaType
Enum to define the specific type of a formal if the Cell has the type Cell.CellType....
Class implementing a legacy password, based on the proprietary hashing algorithm of Excel.
PasswordType
Target type of the password.
Class to register plug-in classes that extends the functionality of NanoXLSX (Core or any other packa...
static bool Initialize()
Initializes the plug-in loader process. If already initialized, the method returns without action.
bool Equals(AbstractStyle other)
Method to compare two objects for sorting purpose.
Factory class with the most important predefined styles.
static Style MergeCellStyle
Gets the style used when merging cells.
bool ForceApplyAlignment
Gets or sets whether the applyAlignment property (used to merge cells) will be defined in the XF entr...
Definition CellXf.cs:120
Class representing a Style with sub classes within a style sheet. An instance of this class is only a...
Definition Style.cs:18
override AbstractStyle Copy()
Method to copy the current object to a new one without casting.
Definition Style.cs:206
CellXf CurrentCellXf
Gets or sets the current CellXf object of the style.
Definition Style.cs:33
Style Append(AbstractStyle styleToAppend)
Appends the specified style parts to the current one. The parts can be instances of sub-classes like ...
Definition Style.cs:121
General data utils class with static methods.
Definition DataUtils.cs:21
static IReadOnlyList< Range > MergeRange(List< Range > givenRanges, Range newRange, RangeMergeStrategy strategy=RangeMergeStrategy.MergeColumns)
Merges a range with a list of given ranges. If there is no intersection between the list and the new ...
Definition DataUtils.cs:345
static IReadOnlyList< Range > SubtractRange(List< Range > givenRanges, Range rangeToRemove, RangeMergeStrategy strategy=RangeMergeStrategy.MergeColumns)
Subtracts a range form a list of given ranges. If the range to be removed does not intersect any of t...
Definition DataUtils.cs:429
Class providing static methods to parse string values to specific types or to print object as languag...
static string ToUpper(string input)
Transforms a string to upper case with null check and invariant culture.
Class providing general validator methods.
Definition Validators.cs:13
static void ValidateWorksheetName(string name)
Validates the passed string, whether it is an expression that can be used as worksheet name.
Class representing a workbook.
Definition Workbook.cs:25
List< Worksheet > Worksheets
Gets the list of worksheets in the workbook.
Definition Workbook.cs:132
Dictionary< int, bool > HiddenRows
Gets the hidden rows as dictionary with the zero-based row number as key and a boolean as value....
Definition Worksheet.cs:299
Cell FirstCellByValue(object searchValue)
Searches for the first occurrence of the value.
int GetFirstDataRowNumber()
Gets the first existing row number with data in the current worksheet (zero-based).
static readonly int MaxWorksheetNameLength
Maximum number of characters a worksheet name can have.
Definition Worksheet.cs:37
void SetStyle(Range cellRange, Style style)
Sets the passed style on the passed cell range. If cells are already existing, the style will be adde...
float DefaultColumnWidth
Gets or sets the default column width.
Definition Worksheet.cs:265
void AddCellFormula(string formula, string address, Style style)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the defined cell ad...
Definition Worksheet.cs:844
WorksheetPane
Enum to define the pane position or active pane in a slip worksheet.
Definition Worksheet.cs:164
@ TopRight
The pane is located in the top right of the split worksheet.
Definition Worksheet.cs:168
@ BottomRight
The pane is located in the bottom right of the split worksheet.
Definition Worksheet.cs:166
@ BottomLeft
The pane is located in the bottom left of the split worksheet.
Definition Worksheet.cs:170
@ TopLeft
The pane is located in the top left of the split worksheet.
Definition Worksheet.cs:172
void SetHorizontalSplit(float topPaneHeight, Address topLeftCell, WorksheetPane? activePane)
Sets the horizontal split of the worksheet into two panes. The measurement in characters cannot be us...
float DefaultRowHeight
Gets or sets the default Row height.
Definition Worksheet.cs:282
int ZoomFactor
Gets or sets the zoom factor of the ViewType of the current worksheet. If AutoZoomFactor,...
Definition Worksheet.cs:521
void GoToNextRow()
Moves the current position to the next row (use for a new line).
int SheetID
Gets or sets the internal ID of the worksheet.
Definition Worksheet.cs:331
void RemoveHiddenRow(int rowNumber)
Sets a previously defined, hidden row as visible again.
CellDirection
Enum to define the direction when using AddNextCell method.
Definition Worksheet.cs:113
@ RowToRow
The next cell will be on the same column (A1,A2,A3...).
Definition Worksheet.cs:117
@ ColumnToColumn
The next cell will be on the same row (A1,B1,C1...).
Definition Worksheet.cs:115
@ Disabled
The address of the next cell will be not changed when adding a cell (for manual definition of cell ad...
Definition Worksheet.cs:119
int GetLastColumnNumber()
Gets the last existing column number in the current worksheet (zero-based).
WorksheetPane? ActivePane
Gets the active Pane is splitting is applied. The value is nullable. If null, no splitting was defin...
Definition Worksheet.cs:472
bool ShowRuler
Gets or sets whether a ruler is displayed over the column headers. This value only applies if ViewTyp...
Definition Worksheet.cs:497
int GetCurrentColumnNumber()
Gets the current column number (zero based).
void ClearSelectedCells()
Removes all cell selections of this worksheet.
bool UseSheetProtection
Gets or sets whether the worksheet is protected. If true, protection is enabled.
Definition Worksheet.cs:373
void InsertRow(int rowNumber, int numberOfNewRows)
Inserts 'count' rows below the specified 'rowNumber'. Existing cells are moved down by the number of ...
void SetSheetProtectionPassword(string password)
Sets or removes the password for worksheet protection. If set, UseSheetProtection will be also set to...
Dictionary< SheetViewType, int > ZoomFactors
Gets all defined zoom factors per SheetViewType of the current worksheet. Use SetZoomFactor(SheetView...
Definition Worksheet.cs:536
SheetViewType
Enum to define how a worksheet is displayed in the spreadsheet application (Excel).
Definition Worksheet.cs:179
@ PageBreakPreview
The worksheet is displayed with indicators where the page would break if it were printed.
Definition Worksheet.cs:183
@ PageLayout
The worksheet is displayed like it would be printed.
Definition Worksheet.cs:185
@ Normal
The worksheet is displayed without pagination (default).
Definition Worksheet.cs:181
void GoToNextColumn()
Moves the current position to the next column.
void AddNextCellFormula(string formula, Style style)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the next cell posit...
Definition Worksheet.cs:899
void SetRowHeight(int rowNumber, float height)
Sets the height of the passed row number (zero-based).
Worksheet(string name)
Constructor with worksheet name.
Definition Worksheet.cs:587
int GetFirstColumnNumber()
Gets the first existing column number in the current worksheet (zero-based).
void AddHiddenColumn(int columnNumber)
Sets the defined column as hidden.
CellDirection CurrentCellDirection
Gets or sets the direction when using AddNextCell method.
Definition Worksheet.cs:258
Cell GetCell(Address address)
Gets the cell of the specified address.
IReadOnlyList< Cell > GetRow(int rowNumber)
Gets a row as list of cell objects.
int ReplaceCellValue(object oldValue, object newValue)
Replaces all occurrences of 'oldValue' with 'newValue' and returns the number of replacements.
static readonly int MinColumnNumber
Minimum column number (zero-based) as constant.
Definition Worksheet.cs:54
IReadOnlyList< Address > AddCellReference(DefinedName definedName, int columnNumber, int rowNumber, Style style, object cachedValue=null)
Adds a cell whose content is a reference to a DefinedName in the workbook (either workbook-scoped or ...
Definition Worksheet.cs:961
void AddSelectedCells(string rangeOrAddress)
Adds a range or cell address to the selected cells on this worksheet.
Worksheet Copy()
Creates a (dereferenced) deep copy of this worksheet.
void SetCurrentCellAddress(int columnNumber, int rowNumber)
Set the current cell address.
string MergeCells(string cellRange)
Merges the defined cell range.
IReadOnlyList< Address > AddCellReference(DefinedName definedName, string address, Style style, object cachedValue=null)
Adds a cell whose content is a reference to a DefinedName in the workbook (either workbook-scoped or ...
bool ShowGridLines
Gets or sets whether grid lines are visible on the current worksheet. Default is true.
Definition Worksheet.cs:487
IReadOnlyList< Cell > GetColumn(int columnNumber)
Gets a column as list of cell objects.
Address? GetLastDataCellAddress()
Gets the last existing cell with data in the current worksheet (bottom right).
void AddSelectedCells(Address startAddress, Address endAddress)
Adds a range to the selected cells on this worksheet.
void InsertColumn(int columnNumber, int numberOfNewColumns)
Inserts 'count' columns right of the specified 'columnNumber'. Existing cells are moved to the right ...
SheetProtectionValue
Enum to define the possible protection types when protecting a worksheet.
Definition Worksheet.cs:126
@ PivotTables
If selected, the user can use pivot tables if the worksheets is protected.
Definition Worksheet.cs:155
@ FormatCells
If selected, the user can format cells if the worksheets is protected.
Definition Worksheet.cs:133
@ InsertHyperlinks
If selected, the user can insert hyper links if the worksheets is protected.
Definition Worksheet.cs:143
@ InsertColumns
If selected, the user can insert columns if the worksheets is protected.
Definition Worksheet.cs:139
@ Sort
If selected, the user can sort cells if the worksheets is protected.
Definition Worksheet.cs:151
@ DeleteColumns
If selected, the user can delete columns if the worksheets is protected.
Definition Worksheet.cs:145
@ Scenarios
If selected, the user can edit scenarios if the worksheets is protected.
Definition Worksheet.cs:131
@ DeleteRows
If selected, the user can delete rows if the worksheets is protected.
Definition Worksheet.cs:147
@ FormatColumns
If selected, the user can format columns if the worksheets is protected.
Definition Worksheet.cs:135
@ InsertRows
If selected, the user can insert rows if the worksheets is protected.
Definition Worksheet.cs:141
@ FormatRows
If selected, the user can format rows if the worksheets is protected.
Definition Worksheet.cs:137
@ AutoFilter
If selected, the user can use auto filters if the worksheets is protected.
Definition Worksheet.cs:153
@ Objects
If selected, the user can edit objects if the worksheets is protected.
Definition Worksheet.cs:129
@ SelectUnlockedCells
If selected, the user can select unlocked cells if the worksheets is protected.
Definition Worksheet.cs:157
@ SelectLockedCells
If selected, the user can select locked cells if the worksheets is protected.
Definition Worksheet.cs:149
Style SetColumnDefaultStyle(int columnNumber, Style style)
Sets the default column style of the passed column number (zero-based).
Worksheet(string name, int id, Workbook reference)
Constructor with name and sheet ID.
Definition Worksheet.cs:599
void SetColumnWidth(string columnAddress, float width)
Sets the width of the passed column address.
void SetSplit(float? leftPaneWidth, float? topPaneHeight, Address topLeftCell, WorksheetPane? activePane)
Sets the horizontal and vertical split of the worksheet into four panes. The measurement in character...
Address? GetFirstCellAddress()
Gets the first existing cell in the current worksheet (bottom right).
void AddCellRange(IReadOnlyList< object > values, Range cellRange, Style style)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
void AddHiddenColumn(string columnAddress)
Sets the defined column as hidden.
IReadOnlyList< Cell > GetColumn(string columnAddress)
Gets a column as list of cell objects.
void SetStyle(string addressExpression, Style style)
Sets the passed style on the passed address expression. Such an expression may be a single cell or a ...
static readonly float DefaultWorksheetColumnWidth
Default column width as constant.
Definition Worksheet.cs:41
static readonly float DefaultWorksheetRowHeight
Default row height as constant.
Definition Worksheet.cs:45
Address? GetLastCellAddress()
Gets the last existing cell in the current worksheet (bottom right).
bool HasCell(int columnNumber, int rowNumber)
Gets whether the specified address exists in the worksheet. Existing means that a value was stored at...
static readonly int MaxRowNumber
Maximum row number (zero-based) as constant.
Definition Worksheet.cs:75
int GetLastDataRowNumber()
Gets the last existing row number with data in the current worksheet (zero-based).
void ResetSplit()
Resets splitting of the worksheet into panes, as well as their freezing.
void SetCurrentCellAddress(string address)
Set the current cell address.
void RemoveSelectedCells(Address address)
Removes the given address from the selected cell ranges of this worksheet, if existing.
Address? PaneSplitTopLeftCell
Gets the Top Left cell address of the bottom right pane if applicable and splitting is applied....
Definition Worksheet.cs:450
void ClearActiveStyle()
Clears the active style of the worksheet. All later added calls will contain no style unless another ...
void SetHorizontalSplit(int numberOfRowsFromTop, bool freeze, Address topLeftCell, WorksheetPane? activePane)
Sets the horizontal split of the worksheet into two panes. The measurement in rows can be used to spl...
void RemoveAutoFilter()
Removes auto filters from the worksheet.
void GoToNextRow(int numberOfRows, bool keepColumnPosition=false)
Moves the current position to the next row with the number of cells to move (use for a new line).
string MergeCells(Range cellRange)
Merges the defined cell range.
bool RemoveCell(int columnNumber, int rowNumber)
Removes a previous inserted cell at the defined address.
void AddSelectedCells(Address address)
Adds a single cell address to the selected cells on this worksheet.
void SetSplit(int? numberOfColumnsFromLeft, int? numberOfRowsFromTop, bool freeze, Address topLeftCell, WorksheetPane? activePane)
Sets the horizontal and vertical split of the worksheet into four panes. The measurement in rows and ...
Style SetColumnDefaultStyle(string columnAddress, Style style)
Sets the default column style of the passed column address.
void RemoveSelectedCells(String rangeOrAddress)
Removes the given range or cell address from the selected cell ranges of this worksheet,...
IEnumerable< Cell > CellValues
Gets all cells of the worksheet as an enumerable sequence. Preferred over Cells in performance-critic...
Definition Worksheet.cs:243
void AddCellRange(IReadOnlyList< object > values, Range cellRange)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
void AddAllowedActionOnSheetProtection(SheetProtectionValue typeOfProtection)
Method to add allowed actions if the worksheet is protected. If one or more values are added,...
void SetAutoFilter(string range)
Sets the column auto filter within the defined column range.
static readonly int MaxColumnNumber
Maximum column number (zero-based) as constant.
Definition Worksheet.cs:49
void AddCellFormula(string formula, string address)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the defined cell ad...
Definition Worksheet.cs:826
IReadOnlyList< Address > AddCellReference(DefinedName definedName, string address, object cachedValue=null)
Adds a cell whose content is a reference to a DefinedName in the workbook (either workbook-scoped or ...
Definition Worksheet.cs:997
void SetVerticalSplit(float leftPaneWidth, Address topLeftCell, WorksheetPane? activePane)
Sets the vertical split of the worksheet into two panes. The measurement in characters cannot be used...
void AddCell(object value, int columnNumber, int rowNumber)
Adds an object to the defined cell address. If the type of the value does not match with one of the s...
Definition Worksheet.cs:754
void SetCurrentColumnNumber(int columnNumber)
Sets the current column number (zero based).
Address? GetFirstDataCellAddress()
Gets the first existing cell with data in the current worksheet (bottom right).
void SetVerticalSplit(int numberOfColumnsFromLeft, bool freeze, Address topLeftCell, WorksheetPane? activePane)
Sets the vertical split of the worksheet into two panes. The measurement in columns can be used to sp...
SheetViewType ViewType
Gets or sets how the current worksheet is displayed in the spreadsheet application (Excel).
Definition Worksheet.cs:503
string SheetName
Gets or sets the name of the worksheet.
Definition Worksheet.cs:347
void AddCellFormula(string formula, int columnNumber, int rowNumber)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the defined cell ad...
Definition Worksheet.cs:860
bool HasCell(Address address)
Gets whether the specified address exists in the worksheet. Existing means that a value was stored at...
Workbook WorkbookReference
Gets or sets the Reference to the parent Workbook.
Definition Worksheet.cs:379
const int AutoZoomFactor
Automatic zoom factor of a worksheet.
Definition Worksheet.cs:90
float? PaneSplitTopHeight
Gets the height of the upper, horizontal split pane, measured from the top of the window....
Definition Worksheet.cs:418
Address? PaneSplitAddress
Gets the split address for frozen panes or if pane split was defined in number of columns and / or ro...
Definition Worksheet.cs:462
Cell FirstOrDefaultCell(Func< Cell, bool > predicate)
Searches for the first occurrence of the expression. Example: var cell = worksheet....
Worksheet()
Default Constructor.
Definition Worksheet.cs:555
void RemoveSelectedCells(Range range)
Removes the given range from the selected cell ranges of this worksheet, if existing....
List< Range > SelectedCells
Gets the cell ranges of selected cells of this worksheet. Returns ans empty list if no cells are sele...
Definition Worksheet.cs:323
void SetSheetName(string name)
Validates and sets the worksheet name.
int GetLastDataColumnNumber()
Gets the last existing column number with data in the current worksheet (zero-based).
string MergeCells(Address startAddress, Address endAddress)
Merges the defined cell range.
void AddCellRange(IReadOnlyList< object > values, Address startAddress, Address endAddress, Style style)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
int GetFirstRowNumber()
Gets the first existing row number in the current worksheet (zero-based).
void SetActiveStyle(Style style)
Sets the active style of the worksheet. This style will be assigned to all later added cells.
int GetFirstDataColumnNumber()
Gets the first existing column number with data in the current worksheet (zero-based).
List< SheetProtectionValue > SheetProtectionValues
Gets the list of SheetProtectionValues. These values define the allowed actions if the worksheet is p...
Definition Worksheet.cs:366
void SetZoomFactor(SheetViewType sheetViewType, int zoomFactor)
Sets a zoom factor for a given SheetViewType. If AutoZoomFactor, the zoom factor is set to automatic.
static string SanitizeWorksheetName(string input, Workbook workbook)
Sanitizes a worksheet name.
void SetStyle(Address address, Style style)
Sets the passed style on the passed (singular) cell address. If the cell is already existing,...
void AddHiddenRow(int rowNumber)
Sets the defined row as hidden.
void AddCell(object value, string address)
Adds an object to the defined cell address. If the type of the value does not match with one of the s...
Definition Worksheet.cs:787
static readonly float MinColumnWidth
Minimum column width as constant.
Definition Worksheet.cs:60
void RemoveMergedCells(string range)
Removes the defined merged cell range.
static readonly int MinRowNumber
Minimum row number (zero-based) as constant.
Definition Worksheet.cs:80
void AddNextCell(object value, Style style)
Adds an object to the next cell position. If the type of the value does not match with one of the sup...
Definition Worksheet.cs:635
Dictionary< int, float > RowHeights
Gets defined row heights as dictionary with the zero-based row number as key and the height (float fr...
Definition Worksheet.cs:307
void AddCell(object value, string address, Style style)
Adds an object to the defined cell address. If the type of the value does not match with one of the s...
Definition Worksheet.cs:807
void AddCellRange(IReadOnlyList< object > values, Address startAddress, Address endAddress)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
bool ShowRowColumnHeaders
Gets or sets whether the column and row headers are visible on the current worksheet....
Definition Worksheet.cs:492
virtual IPassword SheetProtectionPassword
Password instance of the worksheet protection. If a password was set, the pain text representation an...
Definition Worksheet.cs:357
const int maxZoomFactor
Maximum zoom factor of a worksheet.
Definition Worksheet.cs:105
void SetColumnWidth(int columnNumber, float width)
Sets the width of the passed column number (zero-based).
static readonly float MaxColumnWidth
Maximum column width as constant.
Definition Worksheet.cs:71
Dictionary< string, Range > MergedCells
Gets the merged cells (only references) as dictionary with the cell address as key and the range obje...
Definition Worksheet.cs:315
void SetSheetName(string name, bool sanitize)
Sets the name of the worksheet.
bool? FreezeSplitPanes
Gets whether split panes are frozen. The value is nullable. If null, no freezing is applied....
Definition Worksheet.cs:440
void AddSelectedCells(Range range)
Adds a range to the selected cells on this worksheet.
const int MaxZoomFactor
Maximum zoom factor of a worksheet.
Definition Worksheet.cs:99
IReadOnlyDictionary< string, Cell > Cells
Gets the cells of the worksheet as read-only dictionary with the cell address string as key and the c...
Definition Worksheet.cs:234
void AddCellRange(IReadOnlyList< object > values, string cellRange, Style style)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
void AddCellRange(IReadOnlyList< object > values, string cellRange)
Adds a list of object values to a defined cell range. If the type of the particular value does not ma...
void AddNextCell(object value)
Adds an object to the next cell position. If the type of the value does not match with one of the sup...
Definition Worksheet.cs:619
IReadOnlyList< Address > AddCellReference(DefinedName definedName, int columnNumber, int rowNumber, object cachedValue=null)
Adds a cell whose content is a reference to a DefinedName in the workbook (either workbook-scoped or ...
Definition Worksheet.cs:923
void RemoveHiddenColumn(int columnNumber)
Sets a previously defined, hidden column as visible again.
void RemoveHiddenColumn(string columnAddress)
Sets a previously defined, hidden column as visible again.
Range? AutoFilterRange
Gets the range of the auto-filter. Wrapped to Nullable to provide null as value. If null,...
Definition Worksheet.cs:225
const int MinZoomFactor
Minimum zoom factor of a worksheet. If set to this value, the zoom is set to automatic.
Definition Worksheet.cs:95
bool RemoveCell(string address)
Removes a previous inserted cell at the defined address.
int GetLastRowNumber()
Gets the last existing row number in the current worksheet (zero-based).
void ResetColumn(int columnNumber)
Resets the defined column, if existing. The corresponding instance will be removed from Columns.
void SetCurrentRowNumber(int rowNumber)
Sets the current row number (zero based).
void AddCell(object value, int columnNumber, int rowNumber, Style style)
Adds an object to the defined cell address. If the type of the value does not match with one of the s...
Definition Worksheet.cs:771
void AddNextCellFormula(string formula)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the next cell posit...
Definition Worksheet.cs:886
void RemoveAllowedActionOnSheetProtection(SheetProtectionValue value)
Removes an allowed action on the current worksheet or its cells.
int GetCurrentRowNumber()
Gets the current row number (zero based).
static readonly float MinRowHeight
Minimum row height as constant.
Definition Worksheet.cs:66
List< Cell > CellsByValue(object searchValue)
Searches for cells that contain the specified value and returns a list of these cells.
Style ActiveStyle
Gets the active Style of the worksheet. If null, no style is defined as active.
Definition Worksheet.cs:480
static readonly float MaxRowHeight
Maximum row height as constant.
Definition Worksheet.cs:85
void AddCellFormula(string formula, int columnNumber, int rowNumber, Style style)
Adds a formula of the type FormulaData.FormulaType.Normal as string expression to the defined cell ad...
Definition Worksheet.cs:874
void RemoveRowHeight(int rowNumber)
Removes the defined, non-standard row height.
void SetStyle(Address startAddress, Address endAddress, Style style)
Sets the passed style on the passed cell range, derived from a start and end address....
void SetAutoFilter(int startColumn, int endColumn)
Sets the column auto filter within the defined column range.
void GoToNextColumn(int numberOfColumns, bool keepRowPosition=false)
Moves the current position to the next column with the number of cells to move.
bool Hidden
gets or sets whether the worksheet is hidden. If true, the worksheet is not listed in the worksheet t...
Definition Worksheet.cs:397
void RemoveSelectedCells(Address startAddress, Address endAddress)
Removes the given range from the selected cell ranges of this worksheet, if existing.
Dictionary< int, Column > Columns
Gets all columns with non-standard properties, like auto filter applied or a special width as diction...
Definition Worksheet.cs:251
float? PaneSplitLeftWidth
Gets the width of the left, vertical split pane, measured from the left of the window....
Definition Worksheet.cs:431
Cell GetCell(int columnNumber, int rowNumber)
Gets the cell of the specified column and row number (zero-based).
Interface to represent a protection password, either for workbooks or worksheets. The implementations...
Definition IPassword.cs:14
Struct representing the cell address as column and row (zero based).
Definition Address.cs:16
int Row
Row number (zero based).
Definition Address.cs:28
string GetAddress()
Returns the combined Address.
Definition Address.cs:84
int Column
Column number (zero based).
Definition Address.cs:24
Struct representing a cell range with a start and end address.
Definition Range.cs:16
override string ToString()
Overwritten ToString method.
Definition Range.cs:136
IReadOnlyList< Address > ResolveEnclosedAddresses()
Gets a list of all addresses between the start and end address.
Definition Range.cs:125
Address StartAddress
Start address of the range.
Definition Range.cs:27
Address EndAddress
End address of the range.
Definition Range.cs:23