198 lines
8.0 KiB
C#
198 lines
8.0 KiB
C#
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<T>(WordTableInfo<T> 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> 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<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;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ValidateInputData<T>(WordTableInfo<T> 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> 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("Объединенные ячейки пересекаются.");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|