149 lines
7.6 KiB
C#
149 lines
7.6 KiB
C#
|
|
namespace QWERTYkez.ExcelProcessor;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Методы расширения для установки границ диапазона.
|
|||
|
|
/// </summary>
|
|||
|
|
public static class RangeBorderExtensions
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Устанавливает границы для диапазона с указанным стилем и цветом.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="range">Диапазон ячеек.</param>
|
|||
|
|
/// <param name="style">Стиль линии границы.</param>
|
|||
|
|
/// <param name="color">Цвет границы (необязательно).</param>
|
|||
|
|
/// <param name="target">Какие границы применять (по умолчанию Outside).</param>
|
|||
|
|
/// <returns>Тот же диапазон для цепочки вызовов.</returns>
|
|||
|
|
public static IRange Set(this IRange range, BorderStyle style, BorderTarget target = BorderTarget.Outside,
|
|||
|
|
System.Drawing.Color? color = null) => range.Set(new() { Style = style, Color = color ?? System.Drawing.Color.Black }, target);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Устанавливает границы для диапазона с указанными параметрами.
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="range">Диапазон ячеек.</param>
|
|||
|
|
/// <param name="borderSide">Стиль и цвет границы.</param>
|
|||
|
|
/// <param name="target">Какие границы применять (по умолчанию Outside).</param>
|
|||
|
|
/// <returns>Тот же диапазон для цепочки вызовов.</returns>
|
|||
|
|
public static IRange Set(this IRange range, BorderSide borderSide, BorderTarget target = BorderTarget.Outside)
|
|||
|
|
{
|
|||
|
|
if (range is null) throw new ArgumentNullException(nameof(range));
|
|||
|
|
if (range is not ExcelRange excelRange)
|
|||
|
|
throw new ArgumentException("Range must be of type ExcelRange", nameof(range));
|
|||
|
|
|
|||
|
|
var writer = excelRange._writer;
|
|||
|
|
var sheet = excelRange._sheet;
|
|||
|
|
uint rowStart = range.RowStart;
|
|||
|
|
uint rowEnd = range.RowEnd;
|
|||
|
|
uint colStart = range.ColStart;
|
|||
|
|
uint colEnd = range.ColEnd;
|
|||
|
|
|
|||
|
|
writer.ThrowIfDisposed();
|
|||
|
|
lock (writer._syncLock)
|
|||
|
|
{
|
|||
|
|
// Определяем, какие стороны нужны для каждой ячейки
|
|||
|
|
for (uint r = rowStart; r <= rowEnd; r++)
|
|||
|
|
{
|
|||
|
|
for (uint c = colStart; c <= colEnd; c++)
|
|||
|
|
{
|
|||
|
|
var cell = new ExcelCell(writer, sheet, r, c);
|
|||
|
|
var newBorder = new CellBorder();
|
|||
|
|
|
|||
|
|
bool isTopRow = (r == rowStart);
|
|||
|
|
bool isBottomRow = (r == rowEnd);
|
|||
|
|
bool isLeftCol = (c == colStart);
|
|||
|
|
bool isRightCol = (c == colEnd);
|
|||
|
|
|
|||
|
|
// В зависимости от target, определяем, какие стороны устанавливать
|
|||
|
|
if (target == BorderTarget.All || target == BorderTarget.Outside)
|
|||
|
|
{
|
|||
|
|
if (isTopRow) newBorder = newBorder with { TopBorder = borderSide };
|
|||
|
|
if (isBottomRow) newBorder = newBorder with { BottomBorder = borderSide };
|
|||
|
|
if (isLeftCol) newBorder = newBorder with { LeftBorder = borderSide };
|
|||
|
|
if (isRightCol) newBorder = newBorder with { RightBorder = borderSide };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (target == BorderTarget.All || target == BorderTarget.Inside)
|
|||
|
|
{
|
|||
|
|
// Внутренние границы: для каждой ячейки устанавливаем правую и нижнюю,
|
|||
|
|
// если есть сосед справа/снизу внутри диапазона
|
|||
|
|
if (c < colEnd) newBorder = newBorder with { RightBorder = borderSide };
|
|||
|
|
if (r < rowEnd) newBorder = newBorder with { BottomBorder = borderSide };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Отдельные стороны
|
|||
|
|
if (target == BorderTarget.Top && isTopRow)
|
|||
|
|
newBorder = newBorder with { TopBorder = borderSide };
|
|||
|
|
if (target == BorderTarget.Bottom && isBottomRow)
|
|||
|
|
newBorder = newBorder with { BottomBorder = borderSide };
|
|||
|
|
if (target == BorderTarget.Left && isLeftCol)
|
|||
|
|
newBorder = newBorder with { LeftBorder = borderSide };
|
|||
|
|
if (target == BorderTarget.Right && isRightCol)
|
|||
|
|
newBorder = newBorder with { RightBorder = borderSide };
|
|||
|
|
|
|||
|
|
// Применяем границу к ячейке (изолированно, без каскада)
|
|||
|
|
cell.SetBorderIsolate(newBorder);
|
|||
|
|
|
|||
|
|
// Если ячейка находится на внешней границе диапазона, очищаем соответствующую сторону у соседа вне диапазона
|
|||
|
|
if (isTopRow && (target == BorderTarget.Outside || target == BorderTarget.All || target == BorderTarget.Top))
|
|||
|
|
ClearNeighborBorder(cell, -1, 0, b => b with { BottomBorder = null });
|
|||
|
|
|
|||
|
|
if (isBottomRow && (target == BorderTarget.Outside || target == BorderTarget.All || target == BorderTarget.Bottom))
|
|||
|
|
ClearNeighborBorder(cell, 1, 0, b => b with { TopBorder = null });
|
|||
|
|
|
|||
|
|
if (isLeftCol && (target == BorderTarget.Outside || target == BorderTarget.All || target == BorderTarget.Left))
|
|||
|
|
ClearNeighborBorder(cell, 0, -1, b => b with { RightBorder = null });
|
|||
|
|
|
|||
|
|
if (isRightCol && (target == BorderTarget.Outside || target == BorderTarget.All || target == BorderTarget.Right))
|
|||
|
|
ClearNeighborBorder(cell, 0, 1, b => b with { LeftBorder = null });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return range;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Очищает все границы в диапазоне (сбрасывает до None).
|
|||
|
|
/// </summary>
|
|||
|
|
public static IRange ClearBorders(this IRange range)
|
|||
|
|
{
|
|||
|
|
if (range is null) throw new ArgumentNullException(nameof(range));
|
|||
|
|
if (range is not ExcelRange excelRange)
|
|||
|
|
throw new ArgumentException("Range must be of type ExcelRange", nameof(range));
|
|||
|
|
|
|||
|
|
var writer = excelRange._writer;
|
|||
|
|
var sheet = excelRange._sheet;
|
|||
|
|
uint rowStart = range.RowStart;
|
|||
|
|
uint rowEnd = range.RowEnd;
|
|||
|
|
uint colStart = range.ColStart;
|
|||
|
|
uint colEnd = range.ColEnd;
|
|||
|
|
|
|||
|
|
writer.ThrowIfDisposed();
|
|||
|
|
lock (writer._syncLock)
|
|||
|
|
{
|
|||
|
|
for (uint r = rowStart; r <= rowEnd; r++)
|
|||
|
|
{
|
|||
|
|
for (uint c = colStart; c <= colEnd; c++)
|
|||
|
|
{
|
|||
|
|
var cell = new ExcelCell(writer, sheet, r, c);
|
|||
|
|
// Удаляем все границы
|
|||
|
|
cell.SetBorderIsolate(new CellBorder()); // пустая граница
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return range;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Вспомогательный метод для очистки конкретной стороны у соседа
|
|||
|
|
static void ClearNeighborBorder(ExcelCell cell, int rowOffset, int colOffset, Func<CellBorder, CellBorder> clearFunc)
|
|||
|
|
{
|
|||
|
|
var neighbor = cell.GetNeighbor(rowOffset, colOffset);
|
|||
|
|
if (neighbor is null)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
var neighborBorder = neighbor.GetCellBorder();
|
|||
|
|
var newBorder = clearFunc(neighborBorder);
|
|||
|
|
if (!neighborBorder.Equals(newBorder))
|
|||
|
|
neighbor.SetBorderIsolate(newBorder);
|
|||
|
|
}
|
|||
|
|
}
|