2026-06-08 14:31:31 +07:00
|
|
|
|
namespace QWERTYkez.ExcelProcessor;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Внутренняя реализация <see cref="IRow"/>.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
internal sealed class ExcelRow : IRow
|
|
|
|
|
|
{
|
2026-06-19 15:06:40 +07:00
|
|
|
|
readonly ExcelWriter _writer;
|
|
|
|
|
|
readonly ExcelSheet _sheet;
|
|
|
|
|
|
uint _rowIndex;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
internal ExcelRow(ExcelWriter writer, ExcelSheet sheet, uint rowIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer = writer;
|
|
|
|
|
|
_sheet = sheet;
|
|
|
|
|
|
_rowIndex = rowIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public uint Index => _rowIndex;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Устанавливает высоту строки без создания объекта IRow.</summary>
|
|
|
|
|
|
internal static void SetHeight(ExcelWriter writer, ExcelSheet sheet, uint rowIndex, RowHeight height)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var row = GetOrCreateRowElementInternal(sheet, rowIndex);
|
|
|
|
|
|
row.Height = height.Points;
|
|
|
|
|
|
row.CustomHeight = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Возвращает высоту строки.</summary>
|
|
|
|
|
|
internal static RowHeight GetHeight(ExcelWriter writer, ExcelSheet sheet, uint rowIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var row = GetRowElementInternal(sheet, rowIndex);
|
|
|
|
|
|
if (row is { } r && r.CustomHeight?.HasValue == true && r.Height?.Value is { } hei)
|
|
|
|
|
|
return RowHeight.FromPoints(hei);
|
|
|
|
|
|
return RowHeight.FromPoints(15.0); // стандартная высота
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Вспомогательные методы
|
2026-06-19 15:06:40 +07:00
|
|
|
|
static Row? GetRowElementInternal(ExcelSheet sheet, uint rowIndex)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
var sheetData = sheet.GetSheetData();
|
|
|
|
|
|
foreach (var row in sheetData.Elements<Row>())
|
|
|
|
|
|
if (row.RowIndex?.Value == rowIndex) return row;
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
static Row GetOrCreateRowElementInternal(ExcelSheet sheet, uint rowIndex)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
var existing = GetRowElementInternal(sheet, rowIndex);
|
|
|
|
|
|
if (existing != null) return existing;
|
|
|
|
|
|
|
|
|
|
|
|
var sheetData = sheet.GetSheetData();
|
|
|
|
|
|
var newRow = new Row { RowIndex = rowIndex };
|
|
|
|
|
|
InsertRowElementInternal(sheetData, newRow, rowIndex);
|
|
|
|
|
|
return newRow;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
static void InsertRowElementInternal(SheetData sheetData, Row row, uint rowIndex)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
bool inserted = false;
|
|
|
|
|
|
foreach (var existing in sheetData.Elements<Row>().ToList())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (existing.RowIndex?.Value > rowIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
existing.InsertBeforeSelf(row);
|
|
|
|
|
|
inserted = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!inserted) sheetData.Append(row);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow MoveTo(uint index)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (index == _rowIndex) return this;
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sheetData = _sheet.GetSheetData();
|
|
|
|
|
|
// Находим элемент строки
|
|
|
|
|
|
var rowElement = FindRowElement(sheetData, _rowIndex);
|
|
|
|
|
|
if (rowElement == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Пустая строка — просто меняем индекс
|
|
|
|
|
|
_rowIndex = index;
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Удаляем из текущей позиции
|
|
|
|
|
|
rowElement.Remove();
|
|
|
|
|
|
// Вставляем в новую позицию
|
|
|
|
|
|
InsertRowElement(sheetData, rowElement, index);
|
|
|
|
|
|
// Обновляем RowIndex в элементе
|
|
|
|
|
|
rowElement.RowIndex = index;
|
|
|
|
|
|
_rowIndex = index;
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public RowHeight Height
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
if (rowElement.Height?.Value is double h && rowElement.CustomHeight?.Value == true)
|
|
|
|
|
|
return RowHeight.FromPoints(h);
|
|
|
|
|
|
// Стандартная высота, если не задана (обычно 15 пунктов)
|
|
|
|
|
|
return RowHeight.FromPoints(15.0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
rowElement.Height = value.Points;
|
|
|
|
|
|
rowElement.CustomHeight = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-19 15:06:40 +07:00
|
|
|
|
private void ApplyStyleToRowCells(CellStyle style)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sheetData = _sheet.GetSheetData();
|
|
|
|
|
|
var rowElement = FindRowElement(sheetData, _rowIndex);
|
|
|
|
|
|
if (rowElement == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// Применяем стиль ко всем существующим ячейкам
|
|
|
|
|
|
foreach (var cellElement in rowElement.Elements<Cell>())
|
|
|
|
|
|
{
|
|
|
|
|
|
var colIndex = GetColumnIndex(cellElement.CellReference?.Value);
|
|
|
|
|
|
if (colIndex > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cell = new ExcelCell(_writer, _sheet, _rowIndex, colIndex);
|
|
|
|
|
|
// Применяем стиль через Set, чтобы объединить с существующим
|
|
|
|
|
|
cell.Set(style);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
static uint GetColumnIndex(string? cellReference)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(cellReference)) return 0;
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
while (i < cellReference!.Length && char.IsLetter(cellReference[i])) i++;
|
|
|
|
|
|
if (i == 0) return 0;
|
|
|
|
|
|
string colPart = cellReference.Substring(0, i);
|
|
|
|
|
|
return CellAddressHelper.ColumnLetterToIndex(colPart);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CellStyle? GetRowStyle(Row rowElement)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (rowElement.StyleIndex?.Value is not uint styleIndex)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
return _writer.GetCellStyle(styleIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2026-06-19 15:06:40 +07:00
|
|
|
|
public IRow Set(NumberFormatPattern format)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
if (format == null) return this;
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
2026-06-19 15:06:40 +07:00
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(format, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Set(CellAlign align)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(align, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Set(CellBorder border)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(border, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Set(CellFill fill)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(fill, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Set(CellFont font)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(font, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Set(CellStyle style)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (style == null) return this;
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
var currentStyle = GetRowStyle(rowElement) ?? new CellStyle();
|
|
|
|
|
|
if (currentStyle.TryMerge(style, out var newStyle))
|
|
|
|
|
|
{
|
|
|
|
|
|
ApplyStyleToRow(newStyle);
|
|
|
|
|
|
ApplyStyleToRowCells(newStyle);
|
|
|
|
|
|
}
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ApplyStyleToRow(CellStyle style)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = GetOrCreateRowElement();
|
|
|
|
|
|
int styleIndex = _writer.GetOrCreateStyleId(style);
|
|
|
|
|
|
rowElement.StyleIndex = (uint)styleIndex;
|
|
|
|
|
|
rowElement.CustomFormat = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-05 15:58:03 +07:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public ICell Cell(uint col) => new ExcelCell(_writer, _sheet, _rowIndex, col);
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow Cell(uint col, Action<ICell> edit)
|
|
|
|
|
|
{
|
|
|
|
|
|
edit(Cell(col)); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, bool value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, string value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
2026-06-19 15:06:40 +07:00
|
|
|
|
Cell(col).SetFormula(value, format); return this;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, DateTime value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, decimal value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, double value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, float value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, int value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(uint col, long value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, Action<ICell> edit)
|
|
|
|
|
|
{
|
|
|
|
|
|
edit(Cell(col)); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, bool value)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, string value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
2026-06-19 15:06:40 +07:00
|
|
|
|
Cell(col).SetFormula(value, format); return this;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, DateTime value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, decimal value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, double value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, float value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, int value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IRow Cell(string col, long value, NumberFormatPattern? format = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Cell(col).Set(value, format); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public ICell Cell(string col) => Cell(CellAddressHelper.ColumnLetterToIndex(col));
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow EditCell(string col, Action<ICell> edit)
|
|
|
|
|
|
{
|
|
|
|
|
|
edit(Cell(col)); return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public void ClearContents()
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = FindRowElement(_sheet.GetSheetData(), _rowIndex);
|
|
|
|
|
|
if (rowElement == null) return;
|
|
|
|
|
|
foreach (var cell in rowElement.Elements<Cell>().ToList())
|
|
|
|
|
|
{
|
|
|
|
|
|
cell.Remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public void ClearFormats()
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var rowElement = FindRowElement(_sheet.GetSheetData(), _rowIndex);
|
|
|
|
|
|
if (rowElement == null) return;
|
|
|
|
|
|
foreach (var cell in rowElement.Elements<Cell>())
|
|
|
|
|
|
{
|
|
|
|
|
|
cell.StyleIndex = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
ClearContents();
|
|
|
|
|
|
ClearFormats();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public void Remove()
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sheetData = _sheet.GetSheetData();
|
|
|
|
|
|
var rowElement = FindRowElement(sheetData, _rowIndex);
|
|
|
|
|
|
rowElement?.Remove();
|
|
|
|
|
|
// Сдвиг индексов последующих строк вниз в Open XML не требуется, т.к. они имеют свои RowIndex.
|
|
|
|
|
|
// Но при последующем доступе по индексам нужно будет корректировать.
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public IRow CopyTo(uint index, out IRow copiedRow)
|
|
|
|
|
|
{
|
|
|
|
|
|
_writer.ThrowIfDisposed();
|
|
|
|
|
|
lock (_writer._syncLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
var sourceRow = FindRowElement(_sheet.GetSheetData(), _rowIndex);
|
|
|
|
|
|
if (sourceRow == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
copiedRow = new ExcelRow(_writer, _sheet, index);
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Клонируем элемент строки
|
|
|
|
|
|
var clonedRow = (Row)sourceRow.CloneNode(true);
|
|
|
|
|
|
clonedRow.RowIndex = index;
|
|
|
|
|
|
// Вставляем в новую позицию
|
|
|
|
|
|
var sheetData = _sheet.GetSheetData();
|
|
|
|
|
|
InsertRowElement(sheetData, clonedRow, index);
|
|
|
|
|
|
copiedRow = new ExcelRow(_writer, _sheet, index);
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Вспомогательные методы
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
Row GetOrCreateRowElement()
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
var sheetData = _sheet.GetSheetData();
|
|
|
|
|
|
var existing = FindRowElement(sheetData, _rowIndex);
|
|
|
|
|
|
if (existing != null) return existing;
|
|
|
|
|
|
var newRow = new Row { RowIndex = _rowIndex };
|
|
|
|
|
|
InsertRowElement(sheetData, newRow, _rowIndex);
|
|
|
|
|
|
return newRow;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
static Row? FindRowElement(SheetData sheetData, uint rowIndex)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
// Поиск по атрибуту RowIndex. В Open XML строки могут идти не по порядку.
|
|
|
|
|
|
foreach (var row in sheetData.Elements<Row>())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (row.RowIndex?.Value == rowIndex)
|
|
|
|
|
|
return row;
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
static void InsertRowElement(SheetData sheetData, Row row, uint rowIndex)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
// Вставка с сохранением сортировки по RowIndex
|
|
|
|
|
|
bool inserted = false;
|
|
|
|
|
|
foreach (var existing in sheetData.Elements<Row>().ToList())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (existing.RowIndex?.Value > rowIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
existing.InsertBeforeSelf(row);
|
|
|
|
|
|
inserted = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!inserted)
|
|
|
|
|
|
sheetData.Append(row);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
int GetOrCreateNumberFormatId(NumberFormatPattern format)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
{
|
|
|
|
|
|
// Создаём стиль, содержащий только числовой формат, и возвращаем его индекс
|
|
|
|
|
|
return _writer.GetOrCreateCellFormatId(numberFormat: format);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|