257 lines
8.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}