257 lines
8.6 KiB
C#
257 lines
8.6 KiB
C#
using DocumentFormat.OpenXml.Packaging;
|
||
using DocumentFormat.OpenXml.Spreadsheet;
|
||
using DocumentFormat.OpenXml;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace ProjectSellPC.DocBuilder
|
||
{
|
||
internal class ExcelBuilder
|
||
{
|
||
private readonly string _filePath;
|
||
private readonly SheetData _sheetData;
|
||
private readonly MergeCells _mergeCells;
|
||
private readonly Columns _columns;
|
||
private uint _rowIndex = 0;
|
||
|
||
public ExcelBuilder(string filePath)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(filePath))
|
||
{
|
||
throw new ArgumentNullException(nameof(filePath));
|
||
}
|
||
if (File.Exists(filePath))
|
||
{
|
||
File.Delete(filePath);
|
||
}
|
||
|
||
_filePath = filePath;
|
||
_sheetData = new SheetData();
|
||
_mergeCells = new MergeCells();
|
||
_columns = new Columns();
|
||
_rowIndex = 1;
|
||
}
|
||
|
||
public ExcelBuilder AddHeader(string header, int startIndex, int count)
|
||
{
|
||
CreateCell(startIndex, _rowIndex, header, StyleIndex.BoldTextWithBorders);
|
||
for (int i = startIndex + 1; i < startIndex + count; ++i)
|
||
{
|
||
CreateCell(i, _rowIndex, "", StyleIndex.BoldTextWithBorders);
|
||
}
|
||
|
||
_mergeCells.Append(new MergeCell()
|
||
{
|
||
Reference = new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}")
|
||
});
|
||
|
||
_rowIndex++;
|
||
return this;
|
||
}
|
||
|
||
public ExcelBuilder AddParagraph(string text, int columnIndex)
|
||
{
|
||
CreateCell(columnIndex, _rowIndex++, text, StyleIndex.SimpleTextWithBorders);
|
||
return this;
|
||
}
|
||
|
||
public ExcelBuilder AddTable(int[] columnsWidths, List<string[]> data)
|
||
{
|
||
if (columnsWidths == null || columnsWidths.Length == 0)
|
||
{
|
||
throw new ArgumentNullException(nameof(columnsWidths));
|
||
}
|
||
|
||
if (data == null || data.Count == 0)
|
||
{
|
||
throw new ArgumentNullException(nameof(data));
|
||
}
|
||
|
||
if (data.Any(x => x.Length != columnsWidths.Length))
|
||
{
|
||
throw new InvalidOperationException("widths.Length != data.Length");
|
||
}
|
||
|
||
uint counter = 1;
|
||
int coef = 2;
|
||
_columns.Append(columnsWidths.Select(x => new Column
|
||
{
|
||
Min = counter,
|
||
Max = counter++,
|
||
Width = x * coef,
|
||
CustomWidth = true
|
||
}));
|
||
|
||
// Добавляем строки таблицы
|
||
for (int i = 0; i < data.Count; ++i)
|
||
{
|
||
var isBoldRow = i == 0 || i == data.Count - 1; // Только заголовок и последняя строка жирные
|
||
var styleIndex = isBoldRow ? StyleIndex.BoldTextWithBorders : StyleIndex.SimpleTextWithBorders;
|
||
|
||
for (int j = 0; j < data[i].Length; ++j)
|
||
{
|
||
CreateCell(j, _rowIndex, data[i][j], styleIndex);
|
||
}
|
||
|
||
_rowIndex++;
|
||
}
|
||
|
||
return this;
|
||
}
|
||
|
||
private enum StyleIndex
|
||
{
|
||
SimpleTextWithoutBorder = 0,
|
||
BoldText = 1,
|
||
SimpleTextWithBorders = 2,
|
||
BoldTextWithBorders = 3
|
||
}
|
||
|
||
public void Build()
|
||
{
|
||
using var spreadsheetDocument = SpreadsheetDocument.Create(_filePath, SpreadsheetDocumentType.Workbook);
|
||
var workbookpart = spreadsheetDocument.AddWorkbookPart();
|
||
GenerateStyle(workbookpart);
|
||
workbookpart.Workbook = new Workbook();
|
||
var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
|
||
worksheetPart.Worksheet = new Worksheet();
|
||
if (_columns.HasChildren)
|
||
{
|
||
worksheetPart.Worksheet.Append(_columns);
|
||
}
|
||
|
||
worksheetPart.Worksheet.Append(_sheetData);
|
||
var sheets = spreadsheetDocument.WorkbookPart!.Workbook.AppendChild(new Sheets());
|
||
var sheet = new Sheet()
|
||
{
|
||
Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
|
||
SheetId = 1,
|
||
Name = "Лист 1"
|
||
};
|
||
|
||
sheets.Append(sheet);
|
||
if (_mergeCells.HasChildren)
|
||
{
|
||
worksheetPart.Worksheet.InsertAfter(_mergeCells, worksheetPart.Worksheet.Elements<SheetData>().First());
|
||
}
|
||
}
|
||
|
||
private static void GenerateStyle(WorkbookPart workbookPart)
|
||
{
|
||
var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
|
||
workbookStylesPart.Stylesheet = new Stylesheet();
|
||
|
||
// Шрифты
|
||
var fonts = new Fonts() { Count = 2 };
|
||
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
|
||
{
|
||
FontSize = new FontSize() { Val = 11 },
|
||
FontName = new FontName() { Val = "Calibri" }
|
||
});
|
||
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
|
||
{
|
||
Bold = new Bold(),
|
||
FontSize = new FontSize() { Val = 11 },
|
||
FontName = new FontName() { Val = "Calibri" }
|
||
});
|
||
|
||
// Заполнение
|
||
var fills = new Fills() { Count = 1 };
|
||
fills.Append(new Fill
|
||
{
|
||
PatternFill = new PatternFill { PatternType = PatternValues.None }
|
||
});
|
||
|
||
// Границы
|
||
var borders = new Borders() { Count = 2 };
|
||
borders.Append(new Border()); // Без границ
|
||
borders.Append(new Border
|
||
{
|
||
LeftBorder = new LeftBorder { Style = BorderStyleValues.Thin },
|
||
RightBorder = new RightBorder { Style = BorderStyleValues.Thin },
|
||
TopBorder = new TopBorder { Style = BorderStyleValues.Thin },
|
||
BottomBorder = new BottomBorder { Style = BorderStyleValues.Thin }
|
||
});
|
||
|
||
// Форматы ячеек
|
||
var cellFormats = new CellFormats() { Count = 4 };
|
||
cellFormats.Append(new CellFormat
|
||
{
|
||
FontId = 0,
|
||
FillId = 0,
|
||
BorderId = 0,
|
||
ApplyFont = true
|
||
}); // Обычный текст без границ
|
||
cellFormats.Append(new CellFormat
|
||
{
|
||
FontId = 1,
|
||
FillId = 0,
|
||
BorderId = 0,
|
||
ApplyFont = true
|
||
}); // Жирный текст без границ
|
||
cellFormats.Append(new CellFormat
|
||
{
|
||
FontId = 0,
|
||
FillId = 0,
|
||
BorderId = 1,
|
||
ApplyFont = true,
|
||
ApplyBorder = true
|
||
}); // Обычный текст с границами
|
||
cellFormats.Append(new CellFormat
|
||
{
|
||
FontId = 1,
|
||
FillId = 0,
|
||
BorderId = 1,
|
||
ApplyFont = true,
|
||
ApplyBorder = true
|
||
}); // Жирный текст с границами
|
||
|
||
workbookStylesPart.Stylesheet.Append(fonts);
|
||
workbookStylesPart.Stylesheet.Append(fills);
|
||
workbookStylesPart.Stylesheet.Append(borders);
|
||
workbookStylesPart.Stylesheet.Append(cellFormats);
|
||
}
|
||
|
||
|
||
|
||
|
||
private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex)
|
||
{
|
||
var columnName = GetExcelColumnName(columnIndex);
|
||
var cellReference = columnName + rowIndex;
|
||
|
||
var row = _sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
|
||
if (row == null)
|
||
{
|
||
row = new Row() { RowIndex = rowIndex };
|
||
_sheetData.Append(row);
|
||
}
|
||
|
||
var cell = new Cell
|
||
{
|
||
CellReference = cellReference,
|
||
StyleIndex = (UInt32Value)(uint)styleIndex,
|
||
CellValue = new CellValue(text),
|
||
DataType = new EnumValue<CellValues>(CellValues.String)
|
||
};
|
||
|
||
row.Append(cell);
|
||
}
|
||
|
||
private static string GetExcelColumnName(int index)
|
||
{
|
||
int div = index;
|
||
string columnName = string.Empty;
|
||
while (div >= 0)
|
||
{
|
||
columnName = (char)(div % 26 + 65) + columnName;
|
||
div = div / 26 - 1;
|
||
}
|
||
return columnName;
|
||
}
|
||
}
|
||
}
|