This commit is contained in:
@@ -8,9 +8,56 @@ namespace QWERTYkez.ExcelProcessor;
|
||||
/// </summary>
|
||||
internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
{
|
||||
|
||||
readonly Dictionary<CellStyle, int> _styleCache = [];
|
||||
|
||||
internal int GetOrCreateStyleId(CellStyle style)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (_styleCache.TryGetValue(style, out int id))
|
||||
return id;
|
||||
|
||||
// Создаём CellFormat через существующий метод GetOrCreateCellFormatId
|
||||
int newId = GetOrCreateCellFormatId(
|
||||
style.NumberFormat,
|
||||
style.Font,
|
||||
style.Fill,
|
||||
style.Border,
|
||||
style.Align
|
||||
);
|
||||
_styleCache[style] = newId;
|
||||
return newId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal CellStyle? GetCellStyle(uint styleIndex)
|
||||
{
|
||||
if (styleIndex == 0) return null;
|
||||
var align = GetCellAlign(styleIndex);
|
||||
var font = GetCellFont(styleIndex);
|
||||
var fill = GetCellFill(styleIndex);
|
||||
var border = GetCellBorder(styleIndex);
|
||||
var numberFormat = GetNumberFormat(styleIndex);
|
||||
bool hasAny = !align.Equals(default) || !font.Equals(default) || !fill.Equals(default) ||
|
||||
!border.Equals(default) || numberFormat != null;
|
||||
if (!hasAny) return null;
|
||||
return new CellStyle
|
||||
{
|
||||
Align = align.Equals(default) ? null : align,
|
||||
Font = font.Equals(default) ? null : font,
|
||||
Fill = fill.Equals(default) ? null : fill,
|
||||
Border = border.Equals(default) ? null : border,
|
||||
NumberFormat = numberFormat
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Работа с общей таблицей строк
|
||||
private SharedStringTablePart? _sharedStringPart;
|
||||
private SharedStringTable? _sharedStringTable;
|
||||
SharedStringTablePart? _sharedStringPart;
|
||||
SharedStringTable? _sharedStringTable;
|
||||
|
||||
internal static Dictionary<int, double>? _calibrationTable; // cw -> width_pts
|
||||
|
||||
@@ -62,7 +109,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return true;
|
||||
}
|
||||
|
||||
private Dictionary<int, double> CalibrateWidthCoeffUsingInterop()
|
||||
Dictionary<int, double> CalibrateWidthCoeffUsingInterop()
|
||||
{
|
||||
object? excelApp = null;
|
||||
object? workbooks = null;
|
||||
@@ -133,7 +180,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
}
|
||||
|
||||
|
||||
private void EnsureSharedStringTable()
|
||||
void EnsureSharedStringTable()
|
||||
{
|
||||
if (_sharedStringPart != null) return;
|
||||
_sharedStringPart = _doc.WorkbookPart?.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
|
||||
@@ -193,17 +240,17 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
}
|
||||
|
||||
// Кэши числовых форматов
|
||||
private readonly Dictionary<string, NumberFormatPattern> _numberFormatCache = [];
|
||||
private readonly Dictionary<uint, NumberFormatPattern> _numberFormatIdToPattern = [];
|
||||
readonly Dictionary<string, NumberFormatPattern> _numberFormatCache = [];
|
||||
readonly Dictionary<uint, NumberFormatPattern> _numberFormatIdToPattern = [];
|
||||
|
||||
// Кэши для компонентов стилей (чтобы не создавать дубликаты)
|
||||
private readonly Dictionary<CellFont, int> _fontCache = [];
|
||||
private readonly Dictionary<CellFill, int> _fillCache = [];
|
||||
private readonly Dictionary<CellBorder, int> _borderCache = [];
|
||||
private readonly Dictionary<CellAlign, int> _alignmentCache = [];
|
||||
readonly Dictionary<CellFont, int> _fontCache = [];
|
||||
readonly Dictionary<CellFill, int> _fillCache = [];
|
||||
readonly Dictionary<CellBorder, int> _borderCache = [];
|
||||
readonly Dictionary<CellAlign, int> _alignmentCache = [];
|
||||
|
||||
// Кэш составных стилей (CellFormat)
|
||||
private readonly Dictionary<(int fontId, int fillId, int borderId, int alignId, int numFmtId), int> _cellFormatCache = [];
|
||||
readonly Dictionary<(int fontId, int fillId, int borderId, int alignId, int numFmtId), int> _cellFormatCache = [];
|
||||
|
||||
// Конструктор, фабричные методы – без изменений (опущены)
|
||||
|
||||
@@ -294,10 +341,8 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
int numFmtId = -1;
|
||||
if (numberFormat != null)
|
||||
{
|
||||
if (numberFormat.Id.HasValue && numberFormat.Id.Value < 164)
|
||||
numFmtId = numberFormat.Id.Value;
|
||||
else
|
||||
numFmtId = (int)GetOrCreateNumberFormatId(numberFormat);
|
||||
numFmtId = numberFormat.Id.HasValue && numberFormat.Id.Value < 164
|
||||
? numberFormat.Id.Value : (int)GetOrCreateNumberFormatId(numberFormat);
|
||||
}
|
||||
|
||||
// Получаем или создаём Font, Fill, Border, Alignment
|
||||
@@ -352,7 +397,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
|
||||
#region Вспомогательные методы для работы со стилями
|
||||
|
||||
private Stylesheet EnsureStylesheet()
|
||||
Stylesheet EnsureStylesheet()
|
||||
{
|
||||
var workbookPart = _doc.WorkbookPart ?? throw new InvalidOperationException("No WorkbookPart");
|
||||
var stylesPart = workbookPart.WorkbookStylesPart;
|
||||
@@ -390,7 +435,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return stylesheet;
|
||||
}
|
||||
|
||||
private uint GetOrCreateNumberFormatId(NumberFormatPattern pattern)
|
||||
uint GetOrCreateNumberFormatId(NumberFormatPattern pattern)
|
||||
{
|
||||
if (pattern.Id.HasValue)
|
||||
return (uint)pattern.Id.Value;
|
||||
@@ -400,7 +445,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return (uint)created.Id!.Value;
|
||||
}
|
||||
|
||||
private int GetOrCreateFontId(CellFont font)
|
||||
int GetOrCreateFontId(CellFont font)
|
||||
{
|
||||
if (_fontCache.TryGetValue(font, out int id))
|
||||
return id;
|
||||
@@ -414,7 +459,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return _fontCache[font] = (int)newId;
|
||||
}
|
||||
|
||||
private int GetOrCreateFillId(CellFill fill)
|
||||
int GetOrCreateFillId(CellFill fill)
|
||||
{
|
||||
if (_fillCache.TryGetValue(fill, out int id))
|
||||
return id;
|
||||
@@ -428,7 +473,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return _fillCache[fill] = (int)newId;
|
||||
}
|
||||
|
||||
private int GetOrCreateBorderId(CellBorder border)
|
||||
int GetOrCreateBorderId(CellBorder border)
|
||||
{
|
||||
if (_borderCache.TryGetValue(border, out int id))
|
||||
return id;
|
||||
@@ -443,7 +488,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return newId;
|
||||
}
|
||||
|
||||
private int GetOrCreateAlignmentId(CellAlign align)
|
||||
int GetOrCreateAlignmentId(CellAlign align)
|
||||
{
|
||||
if (_alignmentCache.TryGetValue(align, out int id))
|
||||
return id;
|
||||
@@ -456,7 +501,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return id;
|
||||
}
|
||||
|
||||
private Alignment GetAlignmentFromCache(int alignId)
|
||||
Alignment GetAlignmentFromCache(int alignId)
|
||||
{
|
||||
foreach (var pair in _alignmentCache)
|
||||
if (pair.Value == alignId)
|
||||
@@ -464,7 +509,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
return new Alignment();
|
||||
}
|
||||
|
||||
private CellFormat? GetCellFormatAt(uint index)
|
||||
CellFormat? GetCellFormatAt(uint index)
|
||||
{
|
||||
var stylesheet = EnsureStylesheet();
|
||||
if (stylesheet.CellFormats == null || index >= stylesheet.CellFormats.Count!.Value)
|
||||
@@ -473,14 +518,14 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
}
|
||||
|
||||
// Вспомогательные создания коллекций
|
||||
private static NumberingFormats CreateNumberingFormats(Stylesheet stylesheet)
|
||||
static NumberingFormats CreateNumberingFormats(Stylesheet stylesheet)
|
||||
{
|
||||
var nfs = new NumberingFormats();
|
||||
stylesheet.NumberingFormats = nfs;
|
||||
return nfs;
|
||||
}
|
||||
|
||||
private static CellFormats CreateCellFormats(Stylesheet stylesheet)
|
||||
static CellFormats CreateCellFormats(Stylesheet stylesheet)
|
||||
{
|
||||
var cfs = new CellFormats();
|
||||
stylesheet.CellFormats = cfs;
|
||||
@@ -491,7 +536,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
|
||||
|
||||
|
||||
private bool _isModified = false;
|
||||
bool _isModified = false;
|
||||
|
||||
internal ExcelWriter() { }
|
||||
|
||||
@@ -1006,7 +1051,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
|
||||
#endregion
|
||||
|
||||
private void EnsureFullCalculationOnLoad()
|
||||
void EnsureFullCalculationOnLoad()
|
||||
{
|
||||
if (_doc?.WorkbookPart?.Workbook == null) return;
|
||||
var workbook = _doc.WorkbookPart.Workbook;
|
||||
@@ -1217,7 +1262,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
|
||||
|
||||
// Внутренний метод, предполагает, что _syncLock уже захвачен вызывающим
|
||||
private NumberFormatPattern CreateNumberFormatInternal(string formatCode)
|
||||
NumberFormatPattern CreateNumberFormatInternal(string formatCode)
|
||||
{
|
||||
// Проверяем кэш по коду
|
||||
if (_numberFormatCache.TryGetValue(formatCode, out var existing))
|
||||
@@ -1257,36 +1302,42 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
|
||||
|
||||
// Вспомогательные методы для извлечения элементов из стилей (нужно закешировать или обращаться напрямую)
|
||||
|
||||
private Border? GetBorderById(uint borderId)
|
||||
Border? GetBorderById(uint borderId)
|
||||
{
|
||||
if (_cachedBorders == null)
|
||||
var borders = EnsureStylesheet().Borders;
|
||||
if (borders == null) return null;
|
||||
int index = 0;
|
||||
foreach (var border in borders.Elements<Border>())
|
||||
{
|
||||
var borders = EnsureStylesheet().Borders;
|
||||
_cachedBorders = borders?.Elements<Border>().ToList() ?? [];
|
||||
if (index == borderId) return border;
|
||||
index++;
|
||||
}
|
||||
return borderId < _cachedBorders.Count ? _cachedBorders[(int)borderId] : null;
|
||||
return null;
|
||||
}
|
||||
private List<Border>? _cachedBorders;
|
||||
|
||||
private Fill? GetFillById(uint borderId)
|
||||
Fill? GetFillById(uint fillId)
|
||||
{
|
||||
if (_cachedFills == null)
|
||||
var fills = EnsureStylesheet().Fills;
|
||||
if (fills == null) return null;
|
||||
int index = 0;
|
||||
foreach (var fill in fills.Elements<Fill>())
|
||||
{
|
||||
var fills = EnsureStylesheet().Fills;
|
||||
_cachedFills = fills?.Elements<Fill>().ToList() ?? [];
|
||||
if (index == fillId) return fill;
|
||||
index++;
|
||||
}
|
||||
return borderId < _cachedFills.Count ? _cachedFills[(int)borderId] : null;
|
||||
return null;
|
||||
}
|
||||
private List<Fill>? _cachedFills;
|
||||
|
||||
private Font? GetFontById(uint borderId)
|
||||
Font? GetFontById(uint fontId)
|
||||
{
|
||||
if (_cachedFonts == null)
|
||||
var fonts = EnsureStylesheet().Fonts;
|
||||
if (fonts == null) return null;
|
||||
int index = 0;
|
||||
foreach (var font in fonts.Elements<Font>())
|
||||
{
|
||||
var borders = EnsureStylesheet().Borders;
|
||||
_cachedFonts = borders?.Elements<Font>().ToList() ?? [];
|
||||
if (index == fontId) return font;
|
||||
index++;
|
||||
}
|
||||
return borderId < _cachedFonts.Count ? _cachedFonts[(int)borderId] : null;
|
||||
return null;
|
||||
}
|
||||
private List<Font>? _cachedFonts;
|
||||
}
|
||||
Reference in New Issue
Block a user