9using System.Collections.Generic;
10using System.Globalization;
24 public class Cell : IComparable<Cell>
27 private const int ASCII_OFFSET = 64;
37#pragma warning disable CA1720
39#pragma warning restore CA1720
96 private Style cellStyle;
97 private int columnNumber;
100 private int rowNumber;
101 private object value;
102 private FeatureSet worksheetFeatures;
138 get {
return cellStyle; }
145 get {
return columnNumber; }
149 columnNumber = value;
159 get {
return dataType; }
162 if (dataType == value)
175 AttachFormulaFeatures();
176 SynchronitzeValueFromFormula();
192 get {
return rowNumber; }
218 if (dataType !=
CellType.Formula || formula ==
null)
222 if (formula.MasterCellAddress ==
null)
224 string expression = GetValueAsFormulaExpression();
225 if (!
string.
Equals(formula.Expression, expression, StringComparison.Ordinal) && formula.DefinedNameReference !=
null)
227 formula.DefinedNameReference =
null;
229 formula.Expression = expression;
243 get {
return formula; }
246 if (ReferenceEquals(formula, value))
250 DetachFormulaFeatures();
252 SynchronitzeValueFromFormula();
253 AttachFormulaFeatures();
332 columnNumber = address.
Column;
333 rowNumber = address.
Row;
348 public Cell(
object value,
CellType type,
int column,
int row) : this(value, type)
390 if (obj ==
null || obj.GetType() != typeof(
Cell))
407 if (this.DataType != other.
DataType)
411 if (this.Value !=
null && other.
Value !=
null && !
this.Value.Equals(other.
Value))
435 internal Range? SetReference(
DefinedName definedName,
object cachedValue =
null)
437 if (definedName ==
null)
439 throw new WorksheetException(
"The defined name to set as cell reference must not be null.");
442 Range? referenceRange =
null;
443 formula.DefinedNameReference = definedName;
444 formula.Expression = definedName.
Name;
448 referenceRange = TransposeDefinedNameArrayRange(definedName.
TextValue);
450 if (definedName.
Type == DefinedName.NameType.Constant)
452 formula.CachedValue = definedName.
TextValue;
453 formula.CachedValueType = FormulaData.ResolveCachedValueType(definedName.
Value);
457 if (cachedValue ==
null || (cachedValue is
string stringValue && stringValue.Length == 0))
459 formula.CachedValueType =
CellType.Number;
463 formula.CachedValueType = FormulaData.ResolveCachedValueType(cachedValue);
465 formula.CachedValue = ParserUtils.ToCachedValueString(cachedValue);
468 this.Formula = formula;
469 this.value = definedName.
Name;
470 return referenceRange;
479 if (this.value ==
null)
487 Type t = this.value.GetType();
488 if (t == typeof(
bool))
490 else if (t == typeof(
byte) || t == typeof(sbyte))
492 else if (t == typeof(decimal))
494 else if (t == typeof(
double))
496 else if (t == typeof(
float))
498 else if (t == typeof(
int) || t == typeof(uint))
500 else if (t == typeof(
long) || t == typeof(ulong))
502 else if (t == typeof(
short) || t == typeof(ushort))
504 else if (t == typeof(DateTime))
510 else if (t == typeof(TimeSpan))
530 if (cellStyle ==
null)
532 lockStyle =
new Style();
538 lockStyle.CurrentCellXf.Locked = isLocked;
539 lockStyle.CurrentCellXf.Hidden = isHidden;
568 dataType = this.dataType,
571 formula = this.formula?.Copy()
573 if (this.cellStyle !=
null)
575 copy.
SetStyle(this.cellStyle,
true);
588 hash = hash * 31 + columnNumber.GetHashCode();
589 hash = hash * 31 + rowNumber.GetHashCode();
591 hash = hash * 31 +
DataType.GetHashCode();
592 hash = hash * 31 + (cellStyle?.GetHashCode() ?? 0);
593 hash = hash * 31 + (value?.GetHashCode() ?? 0);
594 hash = hash * 31 + (
Formula?.GetHashCode() ?? 0);
607 if (ReferenceEquals(left,
null))
609 return ReferenceEquals(right,
null);
612 return left.
Equals(right);
623 return !(left == right);
637 return ReferenceEquals(left,
null) ? !ReferenceEquals(right,
null) : left.
CompareTo(right) < 0;
651 return ReferenceEquals(left,
null) || left.
CompareTo(right) <= 0;
665 return !ReferenceEquals(left,
null) && left.
CompareTo(right) > 0;
679 return ReferenceEquals(left,
null) ? ReferenceEquals(right,
null) : left.
CompareTo(right) >= 0;
684 #region staticMethods
693 List<Cell> output =
new List<Cell>();
701 foreach (T item
in list)
711 if (t == typeof(
Cell))
712 { c = item as
Cell; }
713 else if (t == typeof(
bool))
715 else if (t == typeof(
byte))
717 else if (t == typeof(sbyte))
719 else if (t == typeof(decimal))
721 else if (t == typeof(
double))
723 else if (t == typeof(
float))
725 else if (t == typeof(
int))
727 else if (t == typeof(uint))
729 else if (t == typeof(
long))
731 else if (t == typeof(ulong))
733 else if (t == typeof(
short))
735 else if (t == typeof(ushort))
737 else if (t == typeof(DateTime))
742 else if (t == typeof(TimeSpan))
747 else if (t == typeof(
string))
779 public static IEnumerable<Address>
GetCellRange(
string startAddress,
string endAddress)
795 public static IEnumerable<Address>
GetCellRange(
int startColumn,
int startRow,
int endColumn,
int endRow)
818 startColumn = startAddress.
Column;
819 endColumn = endAddress.
Column;
823 startColumn = endAddress.
Column;
824 endColumn = startAddress.
Column;
826 if (startAddress.
Row < endAddress.
Row)
828 startRow = startAddress.
Row;
829 endRow = endAddress.
Row;
833 startRow = endAddress.
Row;
834 endRow = startAddress.
Row;
836 List<Address> output =
new List<Address>();
837 for (
int column = startColumn; column <= endColumn; column++)
839 for (
int row = startRow; row <= endRow; row++)
841 output.Add(
new Address(column, row));
885 return new Address(column, row, type);
912 if (
string.IsNullOrEmpty(address))
914 throw new FormatException(
"The cell address is null or empty and could not be resolved");
918 int len = address.Length;
919 bool fixedCol =
false;
920 bool fixedRow =
false;
923 if (i < len && address[i] ==
'$') { fixedCol =
true; i++; }
927 while (i < len && ((address[i] >=
'A' && address[i] <=
'Z') || (address[i] >=
'a' && address[i] <=
'z')))
933 throw new FormatException(
"The format of the cell address (" + address +
") is malformed");
936 string colPart = address.Substring(colStart, i - colStart);
939 if (i < len && address[i] ==
'$') { fixedRow =
true; i++; }
943 while (i < len && address[i] >=
'0' && address[i] <=
'9')
948 if (i == rowStart || i != len)
950 throw new FormatException(
"The format of the cell address (" + address +
") is malformed");
953 row =
int.Parse(address.Substring(rowStart, i - rowStart), NumberStyles.Integer, CultureInfo.InvariantCulture) - 1;
957 if (fixedCol && fixedRow) { addressType =
AddressType.FixedRowAndColumn; }
958 else if (fixedCol) { addressType =
AddressType.FixedColumn; }
959 else if (fixedRow) { addressType =
AddressType.FixedRow; }
972 if (
string.IsNullOrEmpty(range))
974 throw new FormatException(
"The cell range is null or empty and could not be resolved");
976 if (!range.Contains(
":"))
980 string[] split = range.Split(
':');
981 if (split.Length != 2)
983 throw new FormatException(
"The cell range (" + range +
") is malformed and could not be resolved");
996 if (
String.IsNullOrEmpty(columnAddress))
1004 for (
int i = columnAddress.Length - 1; i >= 0; i--)
1006 chr = columnAddress[i];
1007 chr -= ASCII_OFFSET;
1008 result += (chr * multiplier);
1025 StringBuilder sb =
new StringBuilder();
1027 while (columnNumber > 0)
1030 sb.Insert(0, (
char)(
'A' + (columnNumber % 26)));
1033 return sb.ToString();
1072 throw new RangeException(
"The column number (" + column +
") is out of range. Range is from " +
1086 throw new RangeException(
"The row number (" + row +
") is out of range. Range is from " +
1095 internal void BindFeatures(FeatureSet features)
1097 if (ReferenceEquals(worksheetFeatures, features))
1102 worksheetFeatures = features;
1103 AttachFormulaFeatures();
1109 internal void UnbindFeatures()
1111 DetachFormulaFeatures();
1112 worksheetFeatures =
null;
1118 private void SynchronitzeValueFromFormula()
1120 if (formula.MasterCellAddress ==
null)
1122 this.value = formula.Expression;
1129 private void AttachFormulaFeatures()
1131 if (worksheetFeatures !=
null && dataType ==
CellType.Formula && formula !=
null)
1133 formula.Features.Add(worksheetFeatures);
1140 private void ClearFormula()
1142 DetachFormulaFeatures();
1149 private void DetachFormulaFeatures()
1151 if (worksheetFeatures !=
null && dataType ==
CellType.Formula && formula !=
null)
1153 formula.Features.Remove(worksheetFeatures);
1161 private string GetValueAsFormulaExpression()
1163 return value ==
null ? null : value.ToString();
1171 private Range TransposeDefinedNameArrayRange(
string referenceExpression)
1173 Range resolvedRange =
new Range(referenceExpression);
1174 int rowCount = resolvedRange.EndAddress.Row - resolvedRange.
StartAddress.
Row;
1175 int columnCount = resolvedRange.EndAddress.Column - resolvedRange.
StartAddress.
Column;
Class representing a cell of a worksheet.
static Address ResolveCellCoordinate(string address)
Gets the column and row number (zero based) of a cell by the address.
static bool operator==(Cell left, Cell right)
Determines whether two Cell instances are equal.
override int GetHashCode()
Gets the hash code of the cell.
static IEnumerable< Address > GetCellRange(Address startAddress, Address endAddress)
Get a list of cell addresses from a cell range.
static IEnumerable< Address > GetCellRange(int startColumn, int startRow, int endColumn, int endRow)
Get a list of cell addresses from a cell range.
CellType
Enum defines the basic data types of a cell.
@ String
Type for single characters and strings.
@ Date
Type for dates (Note: Dates before 1900-01-01 and after 9999-12-31 are not allowed).
@ Default
Default Type, not specified.
@ Error
Type for a standalone error value in a cell.
@ Time
Type for times (Note: Internally handled as OAdate, represented by TimeSpan).
@ Number
Type for all numeric types (long, integer, float, double, short, byte and decimal; signed and unsigne...
@ Empty
Type for empty cells. This type is only used for merged cells (all cells except the first of the cell...
Cell()
Default constructor. Cells created with this constructor do not have a link to a worksheet initially.
static IEnumerable< Cell > ConvertArray< T >(IEnumerable< T > list)
Converts a List of supported objects into a list of cells.
void SetCellLockedState(bool isLocked, bool isHidden)
Sets the lock state of the cell.
static void ValidateRowNumber(int row)
Validates the passed (zero-based) row number. An exception will be thrown if the row is invalid.
Address CellAddress2
Gets or sets the combined cell Address as Address object.
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).
static AddressScope GetAddressScope(string addressExpression)
Gets the scope of the passed address (string expression). Scope means either single cell address or r...
static bool operator<(Cell left, Cell right)
Determines whether the first instance of a Cell is less/smaller as the second.
AddressType
Enum for the referencing style of the address.
@ FixedColumn
Column of the address is fixed (e.g. '$C3').
@ FixedRow
Row of the address is fixed (e.g. 'C$3').
@ FixedRowAndColumn
Row and column of the address is fixed (e.g. '$C$3').
Style CellStyle
Gets the assigned style of the cell.
static bool operator>=(Cell left, Cell right)
Determines whether the first instance of a Cell is greater/larger or equal as the second.
static IEnumerable< Address > GetCellRange(string startAddress, string endAddress)
Get a list of cell addresses from a cell range.
static Range ResolveCellRange(string range)
Resolves a cell range from the format like A1:B3 or AAD556:AAD1000.
int RowNumber
Gets or sets the number of the row (zero-based).
static void ValidateColumnNumber(int column)
Validates the passed (zero-based) column number. An exception will be thrown if the column is invalid...
static int ResolveColumn(string columnAddress)
Gets the column number from the column address (A - XFD).
CellType DataType
Gets or sets the type of the cell.
static bool operator!=(Cell left, Cell right)
Determines whether two Cell instances are not equal.
override bool Equals(object obj)
Compares two objects whether they are addresses and equal.
string CellAddress
Gets or sets the combined cell Address as string in the format A1 - XFD1048576. The address may conta...
Cell(object value, CellType type, string address)
Constructor with value, cell type and address as string. The worksheet reference is set to null and m...
AddressScope
Enum to define the scope of a passed address string (used in static context).
@ SingleAddress
The address represents a single cell.
@ Invalid
The address expression is invalid.
@ Range
The address represents a range of cells.
@ Any
The address represents a single cell or a range of cells.
FormulaData Formula
Formula object in case of the cell has the DataType CellType.Formula. Default is null,...
static void ResolveCellCoordinate(string address, out int column, out int row, out AddressType addressType)
Gets the column and row number (zero based) of a cell by the address.
Cell(object value, CellType type, Address address)
Constructor with value, cell type and address as struct. The worksheet reference is set to null and m...
int ColumnNumber
Gets or sets the number of the column (zero-based).
Cell(object value, CellType type, int column, int row)
Constructor with value, cell type, row number and column number.
Cell(object value, CellType type)
Constructor with value and cell type. Cells created with this constructor do not have a link to a wor...
Style SetStyle(Style style, bool unmanaged=false)
Sets the style of the cell.
static IEnumerable< Address > GetCellRange(string range)
Gets a list of cell addresses from a cell range (format A1:B3 or AAD556:AAD1000).
void ResolveCellType()
Method resets the Cell type and tries to find the actual type. This is used if a Cell was created wit...
AddressType CellAddressType
Gets or sets the optional address type that can be part of the cell address.
static bool operator>(Cell left, Cell right)
Determines whether the first instance of a Cell is greater/larger as the second.
static void ResolveCellCoordinate(string address, out int column, out int row)
Gets the column and row number (zero based) of a cell by the address.
object Value
Gets or sets the value of the cell (generic object type). When setting a value, the DataType is autom...
static string ResolveColumnAddress(int columnNumber)
Gets the column address (A - XFD).
static bool operator<=(Cell left, Cell right)
Determines whether the first instance of a Cell is less/smaller or equal as the second.
int CompareTo(Cell other)
Implemented CompareTo method.
void RemoveStyle()
Removes the assigned style from the cell.
Class representing a defined name within a workbook. A defined name is a descriptive text that repres...
object Value
Gets the raw reference of the defined Name. The value will be transformed in its appropriate text val...
string TextValue
Gets the textual reference of the defined name. This is stored verbatim and may be a cell address (e....
NameType Type
Type of the defined name.
string Name
Gets the name of the defined name as it appears in the workbook (e.g. MyRange).
NameType
Enum to specify the type of the defined name.
Static class that contains shared enums for error cases.
FormulaError
Errors that can occur in formulas / functions.
Class for exceptions regarding range incidents (e.g. out-of-range).
Class for exceptions regarding Style incidents.
Class for exceptions regarding worksheet incidents.
bool Equals(AbstractStyle other)
Method to compare two objects for sorting purpose.
Factory class with the most important predefined styles.
static Style TimeFormat
Gets the time format style.
static Style DateFormat
Gets the date format style.
Class to manage all styles at runtime, before writing XLSX files. The main purpose is deduplication a...
static StyleRepository Instance
Gets the singleton instance of the repository.
Style AddStyle(Style style)
Adds a style to the repository and returns the actual reference.
Class representing a Style with sub classes within a style sheet. An instance of this class is only a...
Style CopyStyle()
Method to copy the current object to a new one with casting.
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 representing a worksheet of a workbook.
static readonly int MinColumnNumber
Minimum column number (zero-based) as constant.
static readonly int MaxRowNumber
Maximum row number (zero-based) as constant.
static readonly int MaxColumnNumber
Maximum column number (zero-based) as constant.
static readonly int MinRowNumber
Minimum row number (zero-based) as constant.
Struct representing the cell address as column and row (zero based).
int Row
Row number (zero based).
Cell.AddressType Type
Referencing type of the address.
bool Equals(Address other)
Compares two addresses whether they are equal.
int Column
Column number (zero based).
Struct representing a cell range with a start and end address.
Address StartAddress
Start address of the range.
Address EndAddress
End address of the range.