using Word = Microsoft.Office.Interop.Word; using System.ComponentModel; using RodionovLibrary.NonVisualComponents.HelperModels; 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); 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 = 18; 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.ColumnParameters.Count); table.Borders.Enable = 1; table.Range.Font.Name = "Times New Roman"; table.Range.Font.Size = 11; for (int i = 0; i < tableInfo.ColumnParameters.Count; i++) { table.Columns[i + 1].Width = (float)(tableInfo.ColumnParameters[i].Width * 28.35); } AddTableHeaderRow(table, tableInfo.ColumnParameters, true); AddTableHeaderRow(table, tableInfo.ColumnParameters, false); MergeColumns(table, tableInfo.MergedColumns); AddTableData(table, tableInfo.Items, tableInfo.ColumnParameters); document.SaveAs2(tableInfo.FileName); wordApp.Quit(); } private void AddTableHeaderRow(Word.Table table, List columnParameters, bool isFirstRow) { for (int i = 0; i < columnParameters.Count; i++) { var header = isFirstRow ? columnParameters[i].FirstRowHeader : columnParameters[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 columnParameters) { for (int rowIndex = 0; rowIndex < items.Count; rowIndex++) { var item = items[rowIndex]; for (int colIndex = 0; colIndex < columnParameters.Count; colIndex++) { var property = typeof(T).GetProperty(columnParameters[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 tableInfo) { if (string.IsNullOrEmpty(tableInfo.FileName) || string.IsNullOrEmpty(tableInfo.Title)) { throw new ArgumentException("Не все данные заполнены"); } CheckColumnParameters(tableInfo.ColumnParameters); if (tableInfo.Items == null || tableInfo.Items.Count == 0) { throw new ArgumentException("Данные для основной части таблицы не заданы"); } foreach (var column in tableInfo.ColumnParameters) { if (typeof(T).GetProperty(column.PropertyName) == null) { throw new ArgumentException($"Свойство '{column.PropertyName}' не найдено в классе {typeof(T).Name}."); } } ValidateMergedColumns(tableInfo.MergedColumns, tableInfo.ColumnParameters.Count); } private void CheckColumnParameters(List columnParameters) { if (columnParameters == null || columnParameters.Count == 0) { throw new ArgumentException("Не заданы колонки для таблицы"); } foreach (var column in columnParameters) { 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("Объединенные ячейки пересекаются."); } } } } }