Третий компонент и переход на Interop

This commit is contained in:
Илья 2024-09-29 23:39:10 +04:00
parent d990fdb00f
commit d7251322f3
11 changed files with 347 additions and 172 deletions

View File

@ -0,0 +1,15 @@
namespace RodionovLibrary.NonVisualComponents.HelperEnums
{
public enum DiagramLegendLayout
{
None,
Left,
Top,
Right,
Bottom
}
}

View File

@ -0,0 +1,11 @@
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class SeriesParameters
{
public string SeriesName { get; set; } = string.Empty;
public List<double> ValuesY { get; set; } = new();
public Color Color { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using RodionovLibrary.NonVisualComponents.HelperEnums;
namespace RodionovLibrary.NonVisualComponents.HelperModels
{
public class WordDiagramInfo
{
public string FileName { get; set; } = string.Empty;
public string DocumentTitle { get; set; } = string.Empty;
public string DiagramTitle { get; set; } = string.Empty;
public DiagramLegendLayout LegendLayout { get; set; }
public List<string> CategoriesX { get; set; } = new();
public List<SeriesParameters> SeriesParameters { get; set; } = new();
}
}

View File

@ -1,4 +1,8 @@
using System.ComponentModel;
using RodionovLibrary.NonVisualComponents.HelperEnums;
using RodionovLibrary.NonVisualComponents.HelperModels;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;
using System.ComponentModel;
namespace RodionovLibrary.NonVisualComponents
{
@ -15,5 +19,110 @@ namespace RodionovLibrary.NonVisualComponents
InitializeComponent();
}
public void CreateDiagramDocument(WordDiagramInfo diagramInfo)
{
ValidateDiagramInfo(diagramInfo);
var wordApp = new Word.Application();
var document = wordApp.Documents.Add();
AddTitle(document, diagramInfo.DocumentTitle);
AddChart(document, diagramInfo);
document.SaveAs2(diagramInfo.FileName);
wordApp.Quit();
}
private void AddTitle(Word.Document document, string title)
{
var paragraph = document.Paragraphs.Add();
paragraph.Range.Text = title;
paragraph.Range.Font.Size = 24;
paragraph.Range.Font.Bold = 1;
paragraph.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
paragraph.Range.InsertParagraphAfter();
}
private void AddChart(Word.Document document, WordDiagramInfo diagramInfo)
{
var paragraph = document.Paragraphs.Add();
var chartShape = document.InlineShapes.AddChart2(-1, (Microsoft.Office.Core.XlChartType)Excel.XlChartType.xlLine, paragraph.Range);
var chart = chartShape.Chart;
chart.HasTitle = true;
chart.ChartTitle.Text = diagramInfo.DiagramTitle;
var chartSeriesCollection = chart.SeriesCollection();
for (int i = chartSeriesCollection.Count; i >= 1; i--)
{
chartSeriesCollection.Item(i).Delete();
}
var categoriesX = diagramInfo.CategoriesX.ToArray();
for (int i = 0; i < diagramInfo.SeriesParameters.Count; i++)
{
var seriesInfo = diagramInfo.SeriesParameters[i];
var series = chartSeriesCollection.NewSeries();
series.Name = seriesInfo.SeriesName;
series.Values = seriesInfo.ValuesY.ToArray();
series.XValues = categoriesX;
SetSeriesColor(series, seriesInfo.Color);
series.MarkerStyle = Excel.XlMarkerStyle.xlMarkerStyleCircle;
series.MarkerSize = 5;
}
chart.HasLegend = true;
chart.Legend.Position = diagramInfo.LegendLayout switch
{
DiagramLegendLayout.Left => Word.XlLegendPosition.xlLegendPositionLeft,
DiagramLegendLayout.Top => Word.XlLegendPosition.xlLegendPositionTop,
DiagramLegendLayout.Right => Word.XlLegendPosition.xlLegendPositionRight,
DiagramLegendLayout.Bottom => Word.XlLegendPosition.xlLegendPositionBottom,
_ => Word.XlLegendPosition.xlLegendPositionBottom,
};
chart.ChartData.Workbook.Application.Quit();
}
private void SetSeriesColor(dynamic series, Color color)
{
series.Format.Line.ForeColor.RGB = ColorTranslator.ToOle(color);
series.Format.Fill.ForeColor.RGB = ColorTranslator.ToOle(color);
}
private void ValidateDiagramInfo(WordDiagramInfo diagramInfo)
{
if (string.IsNullOrEmpty(diagramInfo.FileName) || string.IsNullOrEmpty(diagramInfo.DocumentTitle) ||
string.IsNullOrEmpty(diagramInfo.DiagramTitle) || diagramInfo.CategoriesX == null ||
diagramInfo.CategoriesX.Count == 0 || diagramInfo.SeriesParameters == null ||
diagramInfo.SeriesParameters.Count == 0)
{
throw new ArgumentException("Не все данные для диаграммы заполнены");
}
foreach (var series in diagramInfo.SeriesParameters)
{
if (string.IsNullOrEmpty(series.SeriesName))
{
throw new ArgumentException("Название серии не может быть пустым");
}
if (series.ValuesY == null || series.ValuesY.Count == 0)
{
throw new ArgumentException($"Список значений оси Y для серии '{series.SeriesName}' не заполнен");
}
if (diagramInfo.CategoriesX.Count != series.ValuesY.Count)
{
throw new ArgumentException($"Количество категорий оси X и значений оси Y для серии '{series.SeriesName}' не совпадает");
}
}
}
}
}

View File

@ -1,16 +1,14 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.Office.Interop.Word;
using RodionovLibrary.NonVisualComponents.HelperModels;
using System.ComponentModel;
using Application = Microsoft.Office.Interop.Word.Application;
namespace RodionovLibrary.NonVisualComponents
{
public partial class WordLongTextComponent : Component
{
private WordprocessingDocument? _wordDocument;
private Body? _docBody;
private Application? _wordApp;
private Document? _document;
public WordLongTextComponent()
{
@ -20,7 +18,6 @@ namespace RodionovLibrary.NonVisualComponents
public WordLongTextComponent(IContainer container)
{
container.Add(this);
InitializeComponent();
}
@ -31,60 +28,54 @@ namespace RodionovLibrary.NonVisualComponents
throw new ArgumentException("Не все данные заполнены");
}
_wordDocument = WordprocessingDocument.Create(textInfo.FileName, WordprocessingDocumentType.Document);
MainDocumentPart mainPart = _wordDocument.AddMainDocumentPart();
mainPart.Document = new Document();
_docBody = mainPart.Document.AppendChild(new Body());
_wordApp = new Application();
_document = _wordApp.Documents.Add();
try
{
AddText(textInfo);
_wordDocument.MainDocumentPart!.Document.Save();
_wordDocument.Dispose();
_document.SaveAs2(textInfo.FileName);
}
finally
{
_document.Close();
_wordApp.Quit();
}
}
private void AddText(WordLongTextInfo textInfo)
{
if (_docBody == null || _wordDocument == null)
if (_document == null)
{
return;
}
AddParagraph(textInfo.Title, fontSize: "48", isBold: true);
AddParagraph(textInfo.Title, fontSize: 22, isBold: true);
foreach (var paragraph in textInfo.Paragraphs)
{
AddParagraph(paragraph, fontSize: "24", isBold: false);
AddParagraph(paragraph, fontSize: 14, isBold: false);
}
}
private void AddParagraph(string text, string fontSize, bool isBold)
private void AddParagraph(string text, int fontSize, bool isBold)
{
if (_docBody == null)
if (_document == null)
{
return;
}
ParagraphProperties paragraphProperties = new();
paragraphProperties.AppendChild(new Justification { Val = JustificationValues.Both });
var paragraph = _document.Content.Paragraphs.Add();
var range = paragraph.Range;
Paragraph paragraph = new();
paragraph.AppendChild(paragraphProperties);
range.Text = text;
range.Font.Size = fontSize;
range.Font.Name = "Times New Roman";
range.Font.Bold = isBold ? 1 : 0;
Run docRun = new();
paragraph.Alignment = WdParagraphAlignment.wdAlignParagraphJustify;
RunProperties runProperties = new();
runProperties.AppendChild(new FontSize { Val = fontSize });
if (isBold)
{
runProperties.AppendChild(new Bold());
}
docRun.AppendChild(runProperties);
docRun.AppendChild(new Text(text));
paragraph.AppendChild(docRun);
_docBody.Append(paragraph);
range.InsertParagraphAfter();
}
private bool CheckData(string[] data)

View File

@ -1,8 +1,6 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using RodionovLibrary.NonVisualComponents.HelperModels;
using Word = Microsoft.Office.Interop.Word;
using System.ComponentModel;
using RodionovLibrary.NonVisualComponents.HelperModels;
namespace RodionovLibrary.NonVisualComponents
{
@ -24,57 +22,101 @@ namespace RodionovLibrary.NonVisualComponents
{
ValidateInputData(tableInfo);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(tableInfo.FileName, WordprocessingDocumentType.Document))
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++)
{
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.ColumnParameters.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);
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);
body.Append(table);
document.SaveAs2(tableInfo.FileName);
wordApp.Quit();
}
mainPart.Document.Save();
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;
}
}
}
@ -118,11 +160,11 @@ namespace RodionovLibrary.NonVisualComponents
}
if (column.Width <= 0)
{
throw new ArgumentException($"У колонки ширина должна быть больше нуля.");
throw new ArgumentException("Ширина колонки должна быть больше нуля.");
}
if (string.IsNullOrEmpty(column.PropertyName))
{
throw new ArgumentException($"Свойство не задано для одной из колонок");
throw new ArgumentException("Свойство не задано для одной из колонок.");
}
}
}
@ -151,82 +193,5 @@ namespace RodionovLibrary.NonVisualComponents
}
}
}
private void AddTableHeaderRow(Table table, List<ColumnParameters> columnParameters, bool isFirstRow)
{
TableRow headerRow = new();
foreach (var column in columnParameters)
{
var header = isFirstRow ? column.FirstRowHeader : column.SecondRowHeader;
TableCell cell = new(new Paragraph(new Run(new Text(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<Paragraph>().First().Elements<Run>().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<TableRow>().ElementAt(0).Elements<TableCell>().ElementAt(i);
cell.TableCellProperties.Append(new HorizontalMerge { Val = i == startCellIndex ? MergedCellValues.Restart : MergedCellValues.Continue });
}
}
int totalColumns = table.Elements<TableRow>().ElementAt(0).Elements<TableCell>().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<TableRow>().ElementAt(0).Elements<TableCell>().ElementAt(i);
TableCell secondRowCell = table.Elements<TableRow>().ElementAt(1).Elements<TableCell>().ElementAt(i);
firstRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Restart });
secondRowCell.TableCellProperties.Append(new VerticalMerge { Val = MergedCellValues.Continue });
}
}
}
private void AddTableData<T>(Table table, List<T> items, List<ColumnParameters> 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);
}
}
}
}

View File

@ -8,7 +8,33 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<COMReference Include="Microsoft.Office.Interop.Excel">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>9</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>00020813-0000-0000-c000-000000000046</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="Microsoft.Office.Interop.Word">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>7</VersionMinor>
<VersionMajor>8</VersionMajor>
<Guid>00020905-0000-0000-c000-000000000046</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="Microsoft.Office.Core">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>8</VersionMinor>
<VersionMajor>2</VersionMajor>
<Guid>2df8d04c-5bfa-101b-bde5-00aa0044de52</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
</Project>

View File

@ -1,6 +1,4 @@
using DocumentFormat.OpenXml.ExtendedProperties;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Reflection;
using System.Reflection;
namespace RodionovLibrary.VisualComponents
{

View File

@ -47,6 +47,7 @@
buttonWordText = new Button();
wordLongTextComponent = new RodionovLibrary.NonVisualComponents.WordLongTextComponent(components);
wordTableComponent = new RodionovLibrary.NonVisualComponents.WordTableComponent(components);
wordDiagramComponent = new RodionovLibrary.NonVisualComponents.WordDiagramComponent(components);
panel1.SuspendLayout();
SuspendLayout();
//
@ -271,5 +272,6 @@
private Button buttonWordText;
private RodionovLibrary.NonVisualComponents.WordLongTextComponent wordLongTextComponent;
private RodionovLibrary.NonVisualComponents.WordTableComponent wordTableComponent;
private RodionovLibrary.NonVisualComponents.WordDiagramComponent wordDiagramComponent;
}
}

View File

@ -1,3 +1,4 @@
using RodionovLibrary.NonVisualComponents.HelperEnums;
using RodionovLibrary.NonVisualComponents.HelperModels;
namespace WinForms
@ -156,9 +157,43 @@ namespace WinForms
}
private void ButtonWordDiagram_Click(object sender, EventArgs e)
{
using var dialog = new SaveFileDialog
{
Filter = "docx|*.docx"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
try
{
var series = new List<SeriesParameters>
{
new() {
SeriesName = "Ńĺđč˙ 1",
ValuesY = new List<double> { 10, 15, 20 },
Color = Color.FromArgb(255, 165, 0)
},
new() {
SeriesName = "Ńĺđč˙ 2",
ValuesY = new List<double> { 45, 34, 18 },
Color = Color.FromArgb(105, 105, 105)
},
new() {
SeriesName = "Ńĺđč˙ 3",
ValuesY = new List<double> { 25, 2, 7 },
Color = Color.FromArgb(255, 255, 0)
}
};
wordDiagramComponent.CreateDiagramDocument(new WordDiagramInfo()
{
FileName = dialog.FileName,
DocumentTitle = "Çŕăîëîâîę",
DiagramTitle = "Ňĺńňîâŕ˙ äčŕăđŕěěŕ",
LegendLayout = DiagramLegendLayout.Bottom,
CategoriesX = new List<string> { "ßíâŕđü", "Ôĺâđŕëü", "Ěŕđň" },
SeriesParameters = series
});
MessageBox.Show("Ãîòîâî!");
}
@ -169,3 +204,4 @@ namespace WinForms
}
}
}
}

View File

@ -123,4 +123,7 @@
<metadata name="wordTableComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>210, 17</value>
</metadata>
<metadata name="wordDiagramComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>382, 17</value>
</metadata>
</root>