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(WordTableInfo 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(WordTableInfo 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, 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) { 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().First().Elements().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().ElementAt(0).Elements().ElementAt(i); cell.TableCellProperties.Append(new HorizontalMerge { Val = i == startCellIndex ? MergedCellValues.Restart : MergedCellValues.Continue }); } } int totalColumns = table.Elements().ElementAt(0).Elements().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().ElementAt(0).Elements().ElementAt(i); TableCell secondRowCell = table.Elements().ElementAt(1).Elements().ElementAt(i); firstRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Restart }); secondRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Continue }); } } } private void AddTableData(Table table, List items, List 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); } } } }