2024-09-29 23:39:10 +04:00
|
|
|
|
using Word = Microsoft.Office.Interop.Word;
|
2024-09-22 23:29:54 +04:00
|
|
|
|
using System.ComponentModel;
|
2024-09-29 23:39:10 +04:00
|
|
|
|
using RodionovLibrary.NonVisualComponents.HelperModels;
|
2024-09-22 13:24:14 +04:00
|
|
|
|
|
|
|
|
|
namespace RodionovLibrary.NonVisualComponents
|
|
|
|
|
{
|
|
|
|
|
public partial class WordTableComponent : Component
|
|
|
|
|
{
|
|
|
|
|
public WordTableComponent()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public WordTableComponent(IContainer container)
|
|
|
|
|
{
|
|
|
|
|
container.Add(this);
|
|
|
|
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
}
|
2024-09-22 23:29:54 +04:00
|
|
|
|
|
|
|
|
|
public void CreateTable<T>(WordTableInfo<T> tableInfo)
|
|
|
|
|
{
|
|
|
|
|
ValidateInputData(tableInfo);
|
|
|
|
|
|
2024-09-29 23:39:10 +04:00
|
|
|
|
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> columnParameters, bool isFirstRow)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < columnParameters.Count; i++)
|
2024-09-22 23:29:54 +04:00
|
|
|
|
{
|
2024-09-29 23:39:10 +04:00
|
|
|
|
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<T>(Word.Table table, List<T> items, List<ColumnParameters> 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;
|
|
|
|
|
}
|
2024-09-22 23:29:54 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ValidateInputData<T>(WordTableInfo<T> tableInfo)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(tableInfo.FileName) || string.IsNullOrEmpty(tableInfo.Title))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не все данные заполнены");
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-23 23:27:20 +04:00
|
|
|
|
CheckColumnParameters(tableInfo.ColumnParameters);
|
2024-09-22 23:29:54 +04:00
|
|
|
|
|
|
|
|
|
if (tableInfo.Items == null || tableInfo.Items.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Данные для основной части таблицы не заданы");
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-23 23:27:20 +04:00
|
|
|
|
foreach (var column in tableInfo.ColumnParameters)
|
2024-09-22 23:29:54 +04:00
|
|
|
|
{
|
|
|
|
|
if (typeof(T).GetProperty(column.PropertyName) == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException($"Свойство '{column.PropertyName}' не найдено в классе {typeof(T).Name}.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-23 23:27:20 +04:00
|
|
|
|
ValidateMergedColumns(tableInfo.MergedColumns, tableInfo.ColumnParameters.Count);
|
2024-09-22 23:29:54 +04:00
|
|
|
|
}
|
|
|
|
|
|
2024-09-23 23:27:20 +04:00
|
|
|
|
private void CheckColumnParameters(List<ColumnParameters> columnParameters)
|
2024-09-22 23:29:54 +04:00
|
|
|
|
{
|
|
|
|
|
if (columnParameters == null || columnParameters.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не заданы колонки для таблицы");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var column in columnParameters)
|
|
|
|
|
{
|
2024-09-23 23:27:20 +04:00
|
|
|
|
if (string.IsNullOrEmpty(column.FirstRowHeader) && string.IsNullOrEmpty(column.SecondRowHeader))
|
2024-09-22 23:29:54 +04:00
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Заголовок не задан для одной из колонок в таблице");
|
|
|
|
|
}
|
|
|
|
|
if (column.Width <= 0)
|
|
|
|
|
{
|
2024-09-29 23:39:10 +04:00
|
|
|
|
throw new ArgumentException("Ширина колонки должна быть больше нуля.");
|
2024-09-22 23:29:54 +04:00
|
|
|
|
}
|
2024-09-23 23:27:20 +04:00
|
|
|
|
if (string.IsNullOrEmpty(column.PropertyName))
|
2024-09-22 23:29:54 +04:00
|
|
|
|
{
|
2024-09-29 23:39:10 +04:00
|
|
|
|
throw new ArgumentException("Свойство не задано для одной из колонок.");
|
2024-09-22 23:29:54 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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("Объединенные ячейки пересекаются.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-22 13:24:14 +04:00
|
|
|
|
}
|
|
|
|
|
}
|