using Word = Microsoft.Office.Interop.Word; using WinFormsLibrary.NonVisualComponents.Helpers; using System.ComponentModel; namespace WinFormsLibrary.NonVisualComponents { public partial class WordTable : Component { public WordTable() { InitializeComponent(); } public WordTable(IContainer container) { container.Add(this); InitializeComponent(); } public void CreateTable(WordTableInfo tableInfo) { ValidateInputData(tableInfo); var wordApp = new Word.Application(); var document = wordApp.Documents.Add(); var range = document.Range(); var paragraph = range.Paragraphs.Add(); paragraph.Range.Text = tableInfo.Title; paragraph.Range.Font.Name = "Times New Roman"; paragraph.Range.Font.Size = 20; paragraph.Range.Font.Bold = 1; paragraph.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; paragraph.Range.ParagraphFormat.SpaceAfter = 8; paragraph.Range.InsertParagraphAfter(); var table = document.Tables.Add(paragraph.Range, tableInfo.Items.Count + 2, tableInfo.ColumnInfos.Count); table.Borders.Enable = 1; table.Range.Font.Name = "Times New Roman"; table.Range.Font.Size = 11; for (int i = 0; i < tableInfo.ColumnInfos.Count; i++) { table.Columns[i + 1].Width = (float)(tableInfo.ColumnInfos[i].Width * 28); } AddTableHeaderRow(table, tableInfo.ColumnInfos, true); AddTableHeaderRow(table, tableInfo.ColumnInfos, false); MergeColumns(table, tableInfo.MergedColumns); AddTableData(table, tableInfo.Items, tableInfo.ColumnInfos); document.SaveAs2(tableInfo.Path); wordApp.Quit(); } private void AddTableHeaderRow(Word.Table table, List columnInfos, bool isFirstRow) { for (int i = 0; i < columnInfos.Count; i++) { var header = isFirstRow ? columnInfos[i].FirstRowHeader : columnInfos[i].SecondRowHeader; if (!string.IsNullOrEmpty(header)) { var cell = table.Cell(isFirstRow ? 1 : 2, i + 1); cell.Range.Text = header; cell.Range.Bold = 1; cell.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; cell.VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter; cell.Range.ParagraphFormat.SpaceBefore = 4; cell.Range.ParagraphFormat.SpaceAfter = 4; } } } private void MergeColumns(Word.Table table, List<(int start, int end)> mergedColumns) { for (int i = 1; i <= table.Columns.Count; i++) { bool isMergedHorizontally = mergedColumns.Any(m => m.start <= i - 1 && m.end >= i - 1); if (!isMergedHorizontally) { table.Cell(1, i).Merge(table.Cell(2, i)); } } int xOffset = 0; foreach (var (start, end) in mergedColumns) { var cellStart = table.Cell(1, start + 1 - xOffset); var cellEnd = table.Cell(1, end + 1 - xOffset); string textToKeep = cellStart.Range.Text.TrimEnd('\r', '\a'); cellStart.Merge(cellEnd); cellStart.Range.Text = textToKeep; xOffset += end - start; } } private void AddTableData(Word.Table table, List items, List columnInfos) { for (int rowIndex = 0; rowIndex < items.Count; rowIndex++) { var item = items[rowIndex]; for (int colIndex = 0; colIndex < columnInfos.Count; colIndex++) { var property = typeof(T).GetProperty(columnInfos[colIndex].PropertyName); var value = property?.GetValue(item)?.ToString() ?? string.Empty; table.Cell(rowIndex + 3, colIndex + 1).Range.Text = value; table.Cell(rowIndex + 3, colIndex + 1).Range.Bold = 0; table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; table.Cell(rowIndex + 3, colIndex + 1).VerticalAlignment = Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter; table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.SpaceBefore = 2; table.Cell(rowIndex + 3, colIndex + 1).Range.ParagraphFormat.SpaceAfter = 2; } } } private void ValidateInputData(WordTableInfo wordTableInfo) { if (string.IsNullOrEmpty(wordTableInfo.Path) || (string.IsNullOrEmpty(wordTableInfo.Title))) { throw new ArgumentException("Не все данные заполнены"); } CheckColumnInfo(wordTableInfo.ColumnInfos); foreach (var column in wordTableInfo.ColumnInfos) { if (typeof(T).GetProperty(column.PropertyName) == null) { throw new ArgumentException($"Свойство '{column.PropertyName}' не найдено в классе {typeof(T).Name}."); } } ValidateMergedColumns(wordTableInfo.MergedColumns, wordTableInfo.ColumnInfos.Count); } public void CheckColumnInfo(List columns) { if ((columns == null) || (columns.Count == 0)) { throw new ArgumentException("Нет информации о колонках"); } foreach (var column in columns) { if (string.IsNullOrEmpty(column.FirstRowHeader) && string.IsNullOrEmpty(column.SecondRowHeader)) { throw new ArgumentException("Заголовок не задан для одной из колонок в таблице"); } if (column.Width <= 0) { throw new ArgumentException("Ширина колонки должна быть больше нуля."); } if (string.IsNullOrEmpty(column.PropertyName)) { throw new ArgumentException("Свойство не задано для одной из колонок."); } } } 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("Объединенные ячейки пересекаются."); } } } } }