233 lines
9.9 KiB
C#
233 lines
9.9 KiB
C#
using DocumentFormat.OpenXml.Packaging;
|
||
using DocumentFormat.OpenXml.Wordprocessing;
|
||
using DocumentFormat.OpenXml;
|
||
using RodionovLibrary.NonVisualComponents.HelperModels;
|
||
using System.ComponentModel;
|
||
|
||
namespace RodionovLibrary.NonVisualComponents
|
||
{
|
||
public partial class WordTableComponent : Component
|
||
{
|
||
public WordTableComponent()
|
||
{
|
||
InitializeComponent();
|
||
}
|
||
|
||
public WordTableComponent(IContainer container)
|
||
{
|
||
container.Add(this);
|
||
|
||
InitializeComponent();
|
||
}
|
||
|
||
public void CreateTable<T>(WordTableInfo<T> tableInfo)
|
||
{
|
||
ValidateInputData(tableInfo);
|
||
|
||
using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(tableInfo.FileName, WordprocessingDocumentType.Document))
|
||
{
|
||
MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();
|
||
mainPart.Document = new Document();
|
||
Body body = mainPart.Document.AppendChild(new Body());
|
||
|
||
ParagraphProperties paragraphProperties = new();
|
||
paragraphProperties.AppendChild(new Justification { Val = JustificationValues.Center });
|
||
|
||
Paragraph titleParagraph = new();
|
||
titleParagraph.AppendChild(paragraphProperties);
|
||
|
||
Run docRun = new();
|
||
|
||
RunProperties runProperties = new();
|
||
runProperties.AppendChild(new FontSize { Val = "48" });
|
||
runProperties.AppendChild(new Bold());
|
||
|
||
docRun.AppendChild(runProperties);
|
||
docRun.AppendChild(new Text(tableInfo.Title));
|
||
|
||
titleParagraph.AppendChild(docRun);
|
||
body.Append(titleParagraph);
|
||
|
||
Table table = new();
|
||
|
||
double totalWidthTwips = tableInfo.FirstRowColumnParameters.Sum(column => column.Width) * 566.93;
|
||
TableProperties tableProperties = new(
|
||
new TableBorders(
|
||
new TopBorder { Val = BorderValues.Single, Size = 8 },
|
||
new BottomBorder { Val = BorderValues.Single, Size = 8 },
|
||
new LeftBorder { Val = BorderValues.Single, Size = 8 },
|
||
new RightBorder { Val = BorderValues.Single, Size = 8 },
|
||
new InsideHorizontalBorder { Val = BorderValues.Single, Size = 8 },
|
||
new InsideVerticalBorder { Val = BorderValues.Single, Size = 8 }
|
||
),
|
||
new TableWidth { Width = totalWidthTwips.ToString("F0"), Type = TableWidthUnitValues.Dxa },
|
||
new TableJustification { Val = TableRowAlignmentValues.Center }
|
||
);
|
||
table.AppendChild(tableProperties);
|
||
|
||
AddTableHeaderRow(table, tableInfo.FirstRowColumnParameters);
|
||
AddTableHeaderRow(table, tableInfo.SecondRowColumnParameters);
|
||
|
||
MergeColumns(table, tableInfo.MergedColumns);
|
||
|
||
AddTableData(table, tableInfo.Items, tableInfo.SecondRowColumnParameters);
|
||
|
||
body.Append(table);
|
||
|
||
mainPart.Document.Save();
|
||
}
|
||
}
|
||
|
||
private void ValidateInputData<T>(WordTableInfo<T> tableInfo)
|
||
{
|
||
if (string.IsNullOrEmpty(tableInfo.FileName) || string.IsNullOrEmpty(tableInfo.Title))
|
||
{
|
||
throw new ArgumentException("Не все данные заполнены");
|
||
}
|
||
|
||
CheckColumnParameters(tableInfo.FirstRowColumnParameters, false);
|
||
CheckColumnParameters(tableInfo.SecondRowColumnParameters, true);
|
||
|
||
if (tableInfo.Items == null || tableInfo.Items.Count == 0)
|
||
{
|
||
throw new ArgumentException("Данные для основной части таблицы не заданы");
|
||
}
|
||
|
||
foreach (var column in tableInfo.SecondRowColumnParameters)
|
||
{
|
||
if (typeof(T).GetProperty(column.PropertyName) == null)
|
||
{
|
||
throw new ArgumentException($"Свойство '{column.PropertyName}' не найдено в классе {typeof(T).Name}.");
|
||
}
|
||
}
|
||
|
||
ValidateMergedColumns(tableInfo.MergedColumns, tableInfo.FirstRowColumnParameters.Count);
|
||
}
|
||
|
||
private void CheckColumnParameters(List<ColumnParameters> columnParameters, bool isSecondRow)
|
||
{
|
||
if (columnParameters == null || columnParameters.Count == 0)
|
||
{
|
||
throw new ArgumentException("Не заданы колонки для таблицы");
|
||
}
|
||
|
||
foreach (var column in columnParameters)
|
||
{
|
||
if (string.IsNullOrEmpty(column.Header))
|
||
{
|
||
throw new ArgumentException("Заголовок не задан для одной из колонок в таблице");
|
||
}
|
||
if (column.Width <= 0)
|
||
{
|
||
throw new ArgumentException($"У колонки с заголовком {column.Header} ширина должна быть больше нуля.");
|
||
}
|
||
if (isSecondRow && string.IsNullOrEmpty(column.PropertyName))
|
||
{
|
||
throw new ArgumentException($"Свойство не задано для заголовка: {column.Header}.");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ValidateMergedColumns(List<(int start, int end)> mergedColumns, int totalColumns)
|
||
{
|
||
if (mergedColumns == null || mergedColumns.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
foreach (var (start, end) in mergedColumns)
|
||
{
|
||
if (start < 0 || end >= totalColumns)
|
||
{
|
||
throw new ArgumentException("Индексы объединенных колонок выходят за пределы допустимых значений.");
|
||
}
|
||
|
||
var overlappingRanges = mergedColumns
|
||
.Where(m => m != (start, end))
|
||
.Any(m => m.start <= end && m.end >= start);
|
||
|
||
if (overlappingRanges)
|
||
{
|
||
throw new ArgumentException("Объединенные ячейки пересекаются.");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void AddTableHeaderRow(Table table, List<ColumnParameters> columnParameters)
|
||
{
|
||
TableRow headerRow = new();
|
||
foreach (var column in columnParameters)
|
||
{
|
||
TableCell cell = new(new Paragraph(new Run(new Text(column.Header))));
|
||
TableCellProperties cellProps = new()
|
||
{
|
||
TableCellWidth = new TableCellWidth { Type = TableWidthUnitValues.Dxa, Width = (column.Width * 566.93).ToString("F0") },
|
||
TableCellVerticalAlignment = new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }
|
||
};
|
||
|
||
ParagraphProperties paragraphProperties = new(new Justification { Val = JustificationValues.Center });
|
||
RunProperties runProperties = new() { Bold = new Bold() };
|
||
|
||
cell.Append(cellProps);
|
||
cell.Append(paragraphProperties);
|
||
cell.Elements<Paragraph>().First().Elements<Run>().First().RunProperties = runProperties;
|
||
|
||
headerRow.Append(cell);
|
||
}
|
||
table.Append(headerRow);
|
||
}
|
||
|
||
private void MergeColumns(Table table, List<(int start, int end)> mergedColumns)
|
||
{
|
||
foreach (var (startCellIndex, endCellIndex) in mergedColumns)
|
||
{
|
||
for (int i = startCellIndex; i <= endCellIndex; i++)
|
||
{
|
||
TableCell cell = table.Elements<TableRow>().ElementAt(0).Elements<TableCell>().ElementAt(i);
|
||
cell.TableCellProperties.Append(new HorizontalMerge { Val = i == startCellIndex ? MergedCellValues.Restart : MergedCellValues.Continue });
|
||
}
|
||
}
|
||
|
||
int totalColumns = table.Elements<TableRow>().ElementAt(0).Elements<TableCell>().Count();
|
||
for (int i = 0; i < totalColumns; i++)
|
||
{
|
||
bool isColumnMergedHorizontally = mergedColumns.Any(m => m.start <= i && m.end >= i);
|
||
|
||
if (!isColumnMergedHorizontally)
|
||
{
|
||
TableCell firstRowCell = table.Elements<TableRow>().ElementAt(0).Elements<TableCell>().ElementAt(i);
|
||
TableCell secondRowCell = table.Elements<TableRow>().ElementAt(1).Elements<TableCell>().ElementAt(i);
|
||
|
||
firstRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Restart });
|
||
secondRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Continue });
|
||
}
|
||
}
|
||
}
|
||
|
||
private void AddTableData<T>(Table table, List<T> items, List<ColumnParameters> columnParameters)
|
||
{
|
||
foreach (var item in items)
|
||
{
|
||
TableRow dataRow = new();
|
||
foreach (var column in columnParameters)
|
||
{
|
||
TableCell cell = new(new Paragraph(new Run(new Text(item?.GetType().GetProperty(column.PropertyName)?.GetValue(item)?.ToString() ?? string.Empty))));
|
||
|
||
TableCellProperties cellProps = new()
|
||
{
|
||
TableCellVerticalAlignment = new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }
|
||
};
|
||
|
||
ParagraphProperties paragraphProperties = new(new Justification { Val = JustificationValues.Center });
|
||
|
||
cell.Append(cellProps);
|
||
cell.Append(paragraphProperties);
|
||
|
||
dataRow.Append(cell);
|
||
}
|
||
table.Append(dataRow);
|
||
}
|
||
}
|
||
}
|
||
}
|