many debugs
All checks were successful
Publish NuGet packages / publish (push) Successful in 28s

This commit is contained in:
melekhin
2026-06-19 15:06:40 +07:00
parent 08b39b7bfe
commit e373d4108a
24 changed files with 1569 additions and 632 deletions

View File

@@ -5,9 +5,77 @@
/// </summary>
internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row, uint col) : ICell
{
/// <summary>
/// Возвращает эффективный стиль ячейки с учётом наследования от строки и столбца.
/// </summary>
public CellStyle? GetCellStyle()
{
var cell = GetCellElement();
CellStyle? cellStyle = null;
// 1. Пытаемся получить стиль самой ячейки
if (cell?.StyleIndex?.Value is uint cellStyleIndex)
{
cellStyle = writer.GetCellStyle(cellStyleIndex);
if (cellStyle != null && !cellStyle.IsEmpty())
return cellStyle; // если у ячейки есть свой стиль, он имеет наивысший приоритет
}
// 2. Стиль строки
var sheetData = sheet.GetSheetData();
var rowElement = FindRowElement(sheetData, row);
if (rowElement?.StyleIndex?.Value is uint rowStyleIndex)
{
var rowStyle = writer.GetCellStyle(rowStyleIndex);
if (rowStyle != null && !rowStyle.IsEmpty())
{
// Если у ячейки нет стиля, возвращаем стиль строки
if (cellStyle == null)
return rowStyle;
// Иначе объединяем: стиль ячейки имеет приоритет, но некоторые свойства могут быть не заданы
// (например, если у ячейки только Border, а у строки Fill, то в результате будет и Border, и Fill)
// Объединяем: сначала берём стиль строки, затем накладываем стиль ячейки (перекрывая)
return rowStyle.Merge(cellStyle);
}
}
// 3. Стиль столбца
if (col > 0)
{
var columnElement = ExcelColumn.GetColumnElementInternal(sheet, col);
if (columnElement?.Style?.Value is uint colStyleIndex)
{
var colStyle = writer.GetCellStyle(colStyleIndex);
if (colStyle != null && !colStyle.IsEmpty())
{
// Если нет стиля ячейки и строки, возвращаем стиль столбца
if (cellStyle == null)
return colStyle;
// Иначе объединяем: стиль ячейки + стиль строки (если есть) + стиль столбца
// Сначала объединяем стиль строки и столбца, затем накладываем стиль ячейки
// Но проще: берём стиль ячейки (если есть) и объединяем со стилем столбца
return colStyle.Merge(cellStyle);
}
}
}
// Если ничего нет, возвращаем null
return cellStyle; // может быть null
}
public void ApplyStyle(CellStyle style)
{
var cell = GetOrCreateCellElement();
int styleIndex = writer.GetOrCreateStyleId(style);
cell.StyleIndex = (uint)styleIndex;
}
// Кэш фрагментов богатого текста (только для InlineString)
private List<IRun>? _runsCache;
private bool _cacheValid;
List<IRun>? _runsCache;
bool _cacheValid;
// ---- Реализация ICell (новые методы) ----
@@ -96,35 +164,50 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return TryRemoveRun(index);
}
public ICell Break()
{
EnsureCacheValid();
if (_runsCache != null && _runsCache.Count > 0)
{
var lastRun = _runsCache[_runsCache.Count - 1];
lastRun.Text += "\n";
}
else
{
Run("\n", null);
}
_cacheValid = true;
UpdateCellFromCache();
return this;
}
public ICell Break()
{
EnsureCacheValid();
if (_runsCache != null && _runsCache.Count > 0)
{
var lastRun = _runsCache[_runsCache.Count - 1];
lastRun.Text += "\n";
EnsureWrapTextEnabled();
}
else
{
Run("\n", null);
}
_cacheValid = true;
UpdateCellFromCache();
return this;
}
public ICell Run(string text, RunFormat? format = null)
{
if (string.IsNullOrEmpty(text)) return this;
EnsureCacheValid();
_runsCache ??= [];
_runsCache.Add(new ExcelRun { Text = text, Format = format });
_cacheValid = true;
UpdateCellFromCache();
return this;
}
public ICell Run(string text, RunFormat? format = null)
{
if (string.IsNullOrEmpty(text)) return this;
EnsureCacheValid();
_runsCache ??= [];
_runsCache.Add(new ExcelRun { Text = text, Format = format });
_cacheValid = true;
UpdateCellFromCache();
public ICell RunBreak(string text, RunFormat? format = null)
if (text.Contains('\n'))
EnsureWrapTextEnabled();
return this;
}
private void EnsureWrapTextEnabled()
{
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.Align is null || currentStyle.Align.Value.WrapText != true)
{
var align = (currentStyle.Align ?? new CellAlign()) with { WrapText = true };
Set(align); // вызовет объединение через TryMerge
}
}
public ICell RunBreak(string text, RunFormat? format = null)
{
Run(text, format);
Break();
@@ -307,7 +390,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
// ---- Приватные методы для работы с кэшем ----
private void EnsureCacheValid()
void EnsureCacheValid()
{
if (_cacheValid) return;
lock (writer._syncLock)
@@ -338,7 +421,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
}
}
private string GetStringFromCell(Cell cell)
string GetStringFromCell(Cell cell)
{
if (cell == null) return string.Empty;
if (cell.DataType?.Value == CellValues.SharedString && cell.CellValue != null)
@@ -352,7 +435,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return string.Empty;
}
private void UpdateCellFromCache()
void UpdateCellFromCache()
{
lock (writer._syncLock)
{
@@ -375,61 +458,66 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
}
}
private InlineString BuildInlineStringFromCache()
{
var inline = new InlineString();
if (_runsCache == null) return inline;
foreach (var run in _runsCache)
{
var runElement = new Run();
runElement.Append(new Text(run.Text));
if (run.Format is { } fmt)
{
var rPr = new RunProperties();
if (fmt.IsBold == true) rPr.Append(new Bold());
if (fmt.IsItalic == true) rPr.Append(new Italic());
if (fmt.Underline.HasValue)
{
rPr.Append(new Underline
{
Val = fmt.Underline.Value switch
{
UnderlineStyle.Single => UnderlineValues.Single,
UnderlineStyle.Double => UnderlineValues.Double,
UnderlineStyle.SingleAccounting => UnderlineValues.SingleAccounting,
UnderlineStyle.DoubleAccounting => UnderlineValues.DoubleAccounting,
_ => throw new NotImplementedException(),
}
});
}
if (fmt.IsStrike == true) rPr.Append(new Strike());
if (fmt.Color.HasValue)
{
var excelColor = fmt.Color.Value.ToExcel();
rPr.Append(excelColor);
}
if (fmt.FontSize.HasValue)
rPr.Append(new FontSize { Val = fmt.FontSize.Value });
if (!string.IsNullOrEmpty(fmt.FontFamily))
rPr.Append(new RunFont { Val = fmt.FontFamily });
if (fmt.Vertical.HasValue)
{
var vertAlign = new VerticalTextAlignment
{
Val = fmt.Vertical.Value == VerticalTextRunAlignment.Superscript
? VerticalAlignmentRunValues.Superscript
: VerticalAlignmentRunValues.Subscript
};
rPr.Append(vertAlign);
}
runElement.RunProperties = rPr;
}
inline.Append(runElement);
}
return inline;
}
InlineString BuildInlineStringFromCache()
{
var inline = new InlineString();
if (_runsCache == null) return inline;
foreach (var run in _runsCache)
{
var runElement = new Run();
var textElement = new Text(run.Text);
// Устанавливаем preserve, если текст содержит пробелы или переносы
if (run.Text.Any(c => char.IsWhiteSpace(c)))
textElement.Space = SpaceProcessingModeValues.Preserve;
runElement.Append(textElement);
private static RunFormat MergeRunFormat(RunFormat baseFmt, RunFormat overlay)
if (run.Format is { } fmt)
{
var rPr = new RunProperties();
if (fmt.IsBold == true)
rPr.Append(new Bold());
if (fmt.IsItalic == true)
rPr.Append(new Italic());
if (fmt.Underline.HasValue)
{
rPr.Append(new Underline
{
Val = fmt.Underline.Value switch
{
UnderlineStyle.Single => UnderlineValues.Single,
UnderlineStyle.Double => UnderlineValues.Double,
UnderlineStyle.SingleAccounting => UnderlineValues.SingleAccounting,
UnderlineStyle.DoubleAccounting => UnderlineValues.DoubleAccounting,
_ => throw new NotImplementedException(),
}
});
}
if (fmt.IsStrike == true)
rPr.Append(new Strike());
if (fmt.TryGetExcelColor(out var c))
rPr.Append(c);
if (fmt.FontSize.HasValue)
rPr.Append(new FontSize { Val = fmt.FontSize.Value });
if (!string.IsNullOrEmpty(fmt.FontFamily))
rPr.Append(new RunFont { Val = fmt.FontFamily });
if (fmt.Vertical.HasValue)
{
var vertAlign = new VerticalTextAlignment
{
Val = fmt.Vertical.Value == VerticalTextRunAlignment.Superscript
? VerticalAlignmentRunValues.Superscript
: VerticalAlignmentRunValues.Subscript
};
rPr.Append(vertAlign);
}
runElement.RunProperties = rPr;
}
inline.Append(runElement);
}
return inline;
}
static RunFormat MergeRunFormat(RunFormat baseFmt, RunFormat overlay)
{
return new RunFormat
{
@@ -709,7 +797,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
public double? TryGetNumber() => TryGetNumber(out double v) ? v : null;
public bool TrySet(string formula, NumberFormatPattern? format = null)
public bool TrySetFormula(string formula, NumberFormatPattern? format = null)
{
if (string.IsNullOrEmpty(formula)) return false;
writer.ThrowIfDisposed();
@@ -718,47 +806,52 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
var cell = GetOrCreateCellElement();
cell.CellFormula = new CellFormula(formula);
cell.DataType = null; // формула сама определяет тип
if (format != null)
SetNumberFormatInternal(cell, format);
return true;
if (format != null) Set(cell, format);
return true;
}
}
public ICell Set(string formula, NumberFormatPattern? format = null)
public ICell SetFormula(string formula, NumberFormatPattern? format = null)
{
if (!TrySet(formula, format))
if (!TrySetFormula(formula, format))
throw new InvalidOperationException("Failed to set formula");
return this;
}
public ICell Set(NumberFormatPattern format)
{
if (format == null) return this;
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var cell = GetOrCreateCellElement();
SetNumberFormatInternal(cell, format);
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(format, out var newStyle))
ApplyStyle(newStyle);
return this;
}
return this;
}
}
/// <inheritdoc />
public ICell Set(CellAlign align)
public ICell Set(Cell cell, NumberFormatPattern format)
{
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(format, out var newStyle))
cell.StyleIndex = (uint)writer.GetOrCreateStyleId(newStyle);
return this;
}
}
/// <inheritdoc />
public ICell Set(CellAlign align)
{
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var cell = GetOrCreateCellElement();
int styleIndex = writer.GetOrCreateCellFormatId(
numberFormat: null,
font: null,
fill: null,
border: null,
align: align
);
cell.StyleIndex = (uint)styleIndex;
return this;
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(align, out var newStyle))
ApplyStyle(newStyle);
return this;
}
}
@@ -768,15 +861,39 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var cell = GetOrCreateCellElement();
int styleIndex = writer.GetOrCreateCellFormatId(
numberFormat: null,
font: null,
fill: null,
border: border,
align: null
);
cell.StyleIndex = (uint)styleIndex;
// 1. Применяем границу к текущей ячейке (объединяя с существующей)
var currentStyle = GetCellStyle() ?? new CellStyle();
CellBorder mergedBorder;
bool changed;
if (currentStyle.Border is { } currBorder)
changed = currBorder.TryMerge(border, out mergedBorder);
else
{
mergedBorder = border;
changed = true;
}
if (!changed)
return this;
ApplyStyle(currentStyle with { Border = mergedBorder });
// 2. Каскадное обновление соседей
// Для каждой стороны, которая была установлена (не null), очищаем соответствующую сторону у соседа
if (border.TopBorder.HasValue)
ClearNeighborBorder(-1, 0, b => b with { BottomBorder = null });
if (border.BottomBorder.HasValue)
ClearNeighborBorder(1, 0, b => b with { TopBorder = null });
if (border.LeftBorder.HasValue)
ClearNeighborBorder(0, -1, b => b with { RightBorder = null });
if (border.RightBorder.HasValue)
ClearNeighborBorder(0, 1, b => b with { LeftBorder = null });
// Диагональные границы не влияют на соседей, их не очищаем
return this;
}
}
@@ -787,16 +904,10 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var cell = GetOrCreateCellElement();
int styleIndex = writer.GetOrCreateCellFormatId(
numberFormat: null,
font: null,
fill: fill,
border: null,
align: null
);
cell.StyleIndex = (uint)styleIndex;
return this;
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(fill, out var newStyle))
ApplyStyle(newStyle);
return this;
}
}
@@ -806,19 +917,148 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var cell = GetOrCreateCellElement();
int styleIndex = writer.GetOrCreateCellFormatId(
numberFormat: null,
font: font,
fill: null,
border: null,
align: null
);
cell.StyleIndex = (uint)styleIndex;
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(font, out var newStyle))
ApplyStyle(newStyle);
return this;
}
}
/// <inheritdoc />
public ICell Set(CellStyle style)
{
if (style is null) return this;
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(style, out style))
ApplyStyle(style);
return this;
}
}
void ClearNeighborBorder(int rowOffset, int colOffset, Func<CellBorder, CellBorder> clearFunc)
{
var neighbor = GetNeighbor(rowOffset, colOffset);
if (neighbor is not { } neighbr)
return;
var neighborBorder = neighbr.GetCellBorder();
var newBorder = clearFunc(neighborBorder);
// Если после очистки граница изменилась, применяем изолированно
if (!neighborBorder.Equals(newBorder))
neighbr.SetBorderIsolate(newBorder);
}
internal void SetBorderIsolate(CellBorder border)
{
var currentStyle = GetCellStyle() ?? new CellStyle();
if (currentStyle.TryMerge(border, out var newStyle))
ApplyStyle(newStyle);
}
/// <summary>
/// Возвращает соседнюю ячейку по указанному смещению.
/// </summary>
/// <param name="cell">Исходная ячейка.</param>
/// <param name="rowOffset">Смещение по строкам (положительное вниз).</param>
/// <param name="colOffset">Смещение по столбцам (положительное вправо).</param>
/// <returns>Соседняя ячейка, или null, если она выходит за пределы листа.</returns>
public ExcelCell? GetNeighbor(int rowOffset, int colOffset)
{
// Проверяем, что смещение не равно нулю и координаты не выходят за допустимые пределы (хотя мы не знаем границ листа)
if (rowOffset == 0 && colOffset == 0) return null;
int newRow = (int)row + rowOffset;
int newCol = (int)col + colOffset;
if (newRow < 1 || newCol < 1) return null;
// Excel допускает до 1048576 строк и 16384 столбцов (но мы не будем жестко ограничивать)
// Просто создаём объект ячейки, даже если она не существует физически.
return new ExcelCell(writer, sheet, (uint)newRow, (uint)newCol);
}
internal ICell SetBorderOverride(CellBorder border)
{
writer.ThrowIfDisposed();
lock (writer._syncLock)
{
// Определяем, какие стороны заданы в border
bool hasTop = border.TopBorder.HasValue;
bool hasBottom = border.BottomBorder.HasValue;
bool hasLeft = border.LeftBorder.HasValue;
bool hasRight = border.RightBorder.HasValue;
// Если какая-то сторона задана, то для соседней ячейки на этой стороне мы должны очистить противоположную сторону.
// Например, если мы устанавливаем верхнюю границу у текущей ячейки, то у ячейки сверху нужно очистить нижнюю границу.
// Аналогично для остальных сторон.
if (hasTop)
{
var neighbor = GetNeighbor(-1, 0);
if (neighbor != null)
{
var neighborBorder = neighbor.GetCellBorder();
if (neighborBorder.BottomBorder.HasValue)
{
var newNeighborBorder = neighborBorder with { BottomBorder = null };
// Применяем только границы, не затрагивая другие аспекты стиля
((ExcelCell)neighbor).SetBorderIsolate(newNeighborBorder);
}
}
}
if (hasBottom)
{
var neighbor = GetNeighbor(1, 0);
if (neighbor != null)
{
var neighborBorder = neighbor.GetCellBorder();
if (neighborBorder.TopBorder.HasValue)
{
var newNeighborBorder = neighborBorder with { TopBorder = null };
((ExcelCell)neighbor).SetBorderIsolate(newNeighborBorder);
}
}
}
if (hasLeft)
{
var neighbor = GetNeighbor(0, -1);
if (neighbor != null)
{
var neighborBorder = neighbor.GetCellBorder();
if (neighborBorder.RightBorder.HasValue)
{
var newNeighborBorder = neighborBorder with { RightBorder = null };
((ExcelCell)neighbor).SetBorderIsolate(newNeighborBorder);
}
}
}
if (hasRight)
{
var neighbor = GetNeighbor(0, 1);
if (neighbor != null)
{
var neighborBorder = neighbor.GetCellBorder();
if (neighborBorder.LeftBorder.HasValue)
{
var newNeighborBorder = neighborBorder with { LeftBorder = null };
((ExcelCell)neighbor).SetBorderIsolate(newNeighborBorder);
}
}
}
// Теперь устанавливаем границу для текущей ячейки (изолированно, чтобы не было зацикливания)
((ExcelCell)this).SetBorderIsolate(border);
return this;
}
}
public ICell Set(bool value)
{
writer.ThrowIfDisposed();
@@ -849,9 +1089,10 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
var cell = GetOrCreateCellElement();
cell.DataType = CellValues.Number;
cell.CellValue = new CellValue(value.ToString(CultureInfo.InvariantCulture));
if (format != null)
SetNumberFormatInternal(cell, format);
}
cell.InlineString = null;
cell.CellFormula = null;
if (format != null) Set(cell, format);
}
return this;
}
public ICell Set(float value, NumberFormatPattern? format = null) => Set((double)value, format);
@@ -897,9 +1138,9 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
public ICell CopyTo(uint rowIndex, string colIndex, out ICell copiedCell) =>
CopyTo(rowIndex, CellAddressHelper.ColumnLetterToIndex(colIndex), out copiedCell);
// Private helpers
// helpers
private Cell? GetCellElement()
Cell? GetCellElement()
{
var sheetData = sheet.GetSheetData();
var eRow = FindRowElement(sheetData, row);
@@ -907,27 +1148,37 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return FindCellInRow(eRow, col);
}
private Cell GetOrCreateCellElement()
{
var sheetData = sheet.GetSheetData();
var eRow = GetOrCreateRowElement(sheetData, row);
var cell = FindCellInRow(eRow, col);
if (cell != null) return cell;
cell = new Cell();
string cellRef = CellAddressHelper.ColumnIndexToLetter(col) + row.ToString();
cell.CellReference = cellRef;
InsertCellInRow(eRow, cell, col);
return cell;
}
private Cell GetOrCreateCellElement()
{
var sheetData = sheet.GetSheetData();
var rowElement = GetOrCreateRowElement(sheetData, row);
var cell = FindCellInRow(rowElement, col);
if (cell != null) return cell;
private static Row? FindRowElement(SheetData sheetData, uint rowIndex)
cell = new Cell();
string cellRef = CellAddressHelper.ColumnIndexToLetter(col) + row.ToString();
cell.CellReference = cellRef;
InsertCellInRow(rowElement, cell, col);
// Наследование стиля
var inheritedStyle = GetCellStyle(); // теперь этот метод учитывает строку и столбец
if (inheritedStyle != null && !inheritedStyle.IsEmpty())
{
int styleIndex = writer.GetOrCreateStyleId(inheritedStyle);
cell.StyleIndex = (uint)styleIndex;
}
return cell;
}
static Row? FindRowElement(SheetData sheetData, uint rowIndex)
{
foreach (var eRow in sheetData.Elements<Row>())
if (eRow.RowIndex?.Value == rowIndex) return eRow;
return null;
}
private static Row GetOrCreateRowElement(SheetData sheetData, uint rowIndex)
static Row GetOrCreateRowElement(SheetData sheetData, uint rowIndex)
{
var existing = FindRowElement(sheetData, rowIndex);
if (existing != null) return existing;
@@ -936,7 +1187,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return newRow;
}
private static void InsertRowElement(SheetData sheetData, Row eRow, uint rowIndex)
static void InsertRowElement(SheetData sheetData, Row eRow, uint rowIndex)
{
bool inserted = false;
foreach (var existing in sheetData.Elements<Row>().ToList())
@@ -951,7 +1202,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
if (!inserted) sheetData.Append(eRow);
}
private static Cell? FindCellInRow(Row eRow, uint colIndex)
static Cell? FindCellInRow(Row eRow, uint colIndex)
{
foreach (var cell in eRow.Elements<Cell>())
{
@@ -961,7 +1212,7 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return null;
}
private static void InsertCellInRow(Row eRow, Cell cell, uint colIndex)
static void InsertCellInRow(Row eRow, Cell cell, uint colIndex)
{
string newRef = CellAddressHelper.ColumnIndexToLetter(colIndex) + (eRow.RowIndex?.Value ?? 1).ToString();
cell.CellReference = newRef;
@@ -978,37 +1229,19 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
if (!inserted) eRow.Append(cell);
}
private void InsertCellAt(uint rowIndex, uint colIndex, Cell cell)
void InsertCellAt(uint rowIndex, uint colIndex, Cell cell)
{
var sheetData = sheet.GetSheetData();
var row = GetOrCreateRowElement(sheetData, rowIndex);
InsertCellInRow(row, cell, colIndex);
}
private void SetNumberFormatInternal(Cell cell, NumberFormatPattern format)
{
if (format == null) return;
int styleIndex = writer.GetOrCreateCellFormatId(
numberFormat: format,
font: null,
fill: null,
border: null,
align: null
);
cell.StyleIndex = (uint)styleIndex;
}
private string GetSharedString(uint index)
string GetSharedString(uint index)
{
return writer.GetSharedString(index);
}
private int GetOrAddSharedString(string value)
{
return writer.GetOrAddSharedString(value);
}
private string ExtractTextFromInlineString(InlineString? inlineString)
string ExtractTextFromInlineString(InlineString? inlineString)
{
if (inlineString == null) return string.Empty;
var sb = new System.Text.StringBuilder();
@@ -1020,10 +1253,10 @@ internal sealed class ExcelCell(ExcelWriter writer, ExcelSheet sheet, uint row,
return sb.ToString();
}
private MergeCells? GetMergeCells() =>
MergeCells? GetMergeCells() =>
sheet.Worksheet.GetFirstChild<MergeCells>();
private bool TryParseRangeReference(string reference, out ExcelRange range)
bool TryParseRangeReference(string reference, out ExcelRange range)
{
range = null!;
if (string.IsNullOrEmpty(reference)) return false;