From d99c4b78a08e259f8a7e43f1b111336b1102cb96 Mon Sep 17 00:00:00 2001 From: Zakharov_Rostislav Date: Thu, 26 Sep 2024 18:24:11 +0400 Subject: [PATCH] feat(lab2): do lab2 task 1 complete task2 task2 change test data initialization task3 task2 fix fixes add percents minor fixes --- ComponentLibrary1/ComponentLibrary1.csproj | 17 +- .../HelperEnums/PdfCellsMergeDirections.cs | 14 + .../HelperEnums/PdfDiagramLegendLocation.cs | 16 + .../HelperEnums/PdfParagraphAlignmentType.cs | 15 + .../office_package/HelperModels/IPdfInfo.cs | 14 + .../HelperModels/IPdfPieChartParameters.cs | 16 + .../HelperModels/ITableTextParameters.cs | 15 + .../HelperModels/PdfCellParameters.cs | 16 + .../HelperModels/PdfCellsMergeParameters.cs | 17 ++ .../HelperModels/PdfColumnParameters.cs | 17 ++ .../HelperModels/PdfDiagramSeries.cs | 14 + .../HelperModels/PdfParagraph.cs | 16 + .../HelperModels/PdfRowParameters.cs | 17 ++ .../office_package/ISaveToPdf.cs | 66 +++++ .../office_package/Implements/SaveToPdf.cs | 273 ++++++++++++++++++ .../pdf_diagram/PdfDiagram.Designer.cs | 36 +++ ComponentLibrary1/pdf_diagram/PdfDiagram.cs | 45 +++ .../pdf_diagram/PdfDiagramInfo.cs | 29 ++ .../pdf_image/PdfImage.Designer.cs | 36 +++ ComponentLibrary1/pdf_image/PdfImage.cs | 47 +++ ComponentLibrary1/pdf_image/PdfImageInfo.cs | 24 ++ .../pdf_table/PdfTable.Designer.cs | 36 +++ ComponentLibrary1/pdf_table/PdfTable.cs | 152 ++++++++++ ComponentLibrary1/pdf_table/PdfTableInfo.cs | 29 ++ TestApp1/Form1.Designer.cs | 127 +++++++- TestApp1/Form1.cs | 150 +++++++++- TestApp1/Form1.resx | 9 + 27 files changed, 1246 insertions(+), 17 deletions(-) create mode 100644 ComponentLibrary1/office_package/HelperEnums/PdfCellsMergeDirections.cs create mode 100644 ComponentLibrary1/office_package/HelperEnums/PdfDiagramLegendLocation.cs create mode 100644 ComponentLibrary1/office_package/HelperEnums/PdfParagraphAlignmentType.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/IPdfInfo.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/IPdfPieChartParameters.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/ITableTextParameters.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfCellParameters.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfCellsMergeParameters.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfColumnParameters.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfDiagramSeries.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfParagraph.cs create mode 100644 ComponentLibrary1/office_package/HelperModels/PdfRowParameters.cs create mode 100644 ComponentLibrary1/office_package/ISaveToPdf.cs create mode 100644 ComponentLibrary1/office_package/Implements/SaveToPdf.cs create mode 100644 ComponentLibrary1/pdf_diagram/PdfDiagram.Designer.cs create mode 100644 ComponentLibrary1/pdf_diagram/PdfDiagram.cs create mode 100644 ComponentLibrary1/pdf_diagram/PdfDiagramInfo.cs create mode 100644 ComponentLibrary1/pdf_image/PdfImage.Designer.cs create mode 100644 ComponentLibrary1/pdf_image/PdfImage.cs create mode 100644 ComponentLibrary1/pdf_image/PdfImageInfo.cs create mode 100644 ComponentLibrary1/pdf_table/PdfTable.Designer.cs create mode 100644 ComponentLibrary1/pdf_table/PdfTable.cs create mode 100644 ComponentLibrary1/pdf_table/PdfTableInfo.cs diff --git a/ComponentLibrary1/ComponentLibrary1.csproj b/ComponentLibrary1/ComponentLibrary1.csproj index 060aa1c..5a87b6b 100644 --- a/ComponentLibrary1/ComponentLibrary1.csproj +++ b/ComponentLibrary1/ComponentLibrary1.csproj @@ -1,10 +1,15 @@  - - net6.0-windows - enable - true - enable - + + net6.0-windows + enable + true + enable + True + + + + + diff --git a/ComponentLibrary1/office_package/HelperEnums/PdfCellsMergeDirections.cs b/ComponentLibrary1/office_package/HelperEnums/PdfCellsMergeDirections.cs new file mode 100644 index 0000000..e082104 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperEnums/PdfCellsMergeDirections.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperEnums +{ + public enum PdfCellsMergeDirections + { + Down, + Right + } +} diff --git a/ComponentLibrary1/office_package/HelperEnums/PdfDiagramLegendLocation.cs b/ComponentLibrary1/office_package/HelperEnums/PdfDiagramLegendLocation.cs new file mode 100644 index 0000000..d5e4b38 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperEnums/PdfDiagramLegendLocation.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperEnums +{ + public enum PdfDiagramLegendLocation + { + Left, + Right, + Top, + Bottom, + } +} diff --git a/ComponentLibrary1/office_package/HelperEnums/PdfParagraphAlignmentType.cs b/ComponentLibrary1/office_package/HelperEnums/PdfParagraphAlignmentType.cs new file mode 100644 index 0000000..7a322ee --- /dev/null +++ b/ComponentLibrary1/office_package/HelperEnums/PdfParagraphAlignmentType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperEnums +{ + public enum PdfParagraphAlignmentType + { + Center, + Left, + Right + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/IPdfInfo.cs b/ComponentLibrary1/office_package/HelperModels/IPdfInfo.cs new file mode 100644 index 0000000..31ef925 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/IPdfInfo.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public interface IPdfInfo + { + public string FileName { get; } + public string Title { get; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/IPdfPieChartParameters.cs b/ComponentLibrary1/office_package/HelperModels/IPdfPieChartParameters.cs new file mode 100644 index 0000000..80936b3 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/IPdfPieChartParameters.cs @@ -0,0 +1,16 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public interface IPdfPieChartParameters + { + public string ChartTitle { get; } + public PdfDiagramLegendLocation LegendLocation { get; } + public PdfDiagramSeries Series { get; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/ITableTextParameters.cs b/ComponentLibrary1/office_package/HelperModels/ITableTextParameters.cs new file mode 100644 index 0000000..f3043eb --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/ITableTextParameters.cs @@ -0,0 +1,15 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public interface ITableTextParameters + { + public string Style { get; } + public PdfParagraphAlignmentType ParagraphAlignment { get; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfCellParameters.cs b/ComponentLibrary1/office_package/HelperModels/PdfCellParameters.cs new file mode 100644 index 0000000..9daeb24 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfCellParameters.cs @@ -0,0 +1,16 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfCellParameters : ITableTextParameters + { + public string Text { get; set; } = string.Empty; + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfCellsMergeParameters.cs b/ComponentLibrary1/office_package/HelperModels/PdfCellsMergeParameters.cs new file mode 100644 index 0000000..985355c --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfCellsMergeParameters.cs @@ -0,0 +1,17 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfCellsMergeParameters + { + public int RowIndex = 0; + public int ColumnIndex = 0; + public PdfCellsMergeDirections Direction; + public int CellNumber = 1; + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfColumnParameters.cs b/ComponentLibrary1/office_package/HelperModels/PdfColumnParameters.cs new file mode 100644 index 0000000..d77c7c8 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfColumnParameters.cs @@ -0,0 +1,17 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfColumnParameters : ITableTextParameters + { + public List Texts { get; set; } = new(); + public string Style { get; set; } = string.Empty; + public int ColumnIndex = 0; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfDiagramSeries.cs b/ComponentLibrary1/office_package/HelperModels/PdfDiagramSeries.cs new file mode 100644 index 0000000..8704d49 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfDiagramSeries.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfDiagramSeries + { + public string SeriesName { get; set; } = string.Empty; + public Dictionary Data = new(); + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfParagraph.cs b/ComponentLibrary1/office_package/HelperModels/PdfParagraph.cs new file mode 100644 index 0000000..afabaab --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfParagraph.cs @@ -0,0 +1,16 @@ +using ComponentLibrary1.office_package.HelperEnums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfParagraph + { + public string Text { get; set; } = string.Empty; + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/ComponentLibrary1/office_package/HelperModels/PdfRowParameters.cs b/ComponentLibrary1/office_package/HelperModels/PdfRowParameters.cs new file mode 100644 index 0000000..b1d08f7 --- /dev/null +++ b/ComponentLibrary1/office_package/HelperModels/PdfRowParameters.cs @@ -0,0 +1,17 @@ +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package.HelperModels +{ + public class PdfRowParameters : ITableTextParameters + { + public List Texts { get; set; } = new(); + public string Style { get; set; } = string.Empty; + public PdfParagraphAlignmentType ParagraphAlignment { get; set; } + } +} diff --git a/ComponentLibrary1/office_package/ISaveToPdf.cs b/ComponentLibrary1/office_package/ISaveToPdf.cs new file mode 100644 index 0000000..1f30015 --- /dev/null +++ b/ComponentLibrary1/office_package/ISaveToPdf.cs @@ -0,0 +1,66 @@ +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.office_package +{ + public interface ISaveToPdf + { + /// + /// Создание doc-файла + /// + /// + void CreatePdf(IPdfInfo info); + /// + /// Создание параграфа с текстом + /// + void CreateParagraph(PdfParagraph paragraph); + /// + /// Создание изображения в pdf файле + /// + void CreateImage(byte[] image); + /// + /// Создание таблицы + /// определенной ширины + /// + void CreateTable(); + /// + /// Создание таблицы с заданным количеством столбцов + /// определенной ширины + /// + void CreateTableWithColumns(List columns); + /// + /// Создание таблицы с заданным количеством столбцов + /// + void CreateTableWithColumns(int columnNumber); + /// + /// Создание и заполнение строки + /// + /// + void CreateRow(PdfRowParameters rowParameters); + /// + /// Создание и заполнение столбца + /// + void InsertTextIntoColumn(PdfColumnParameters columnParameters); + /// + /// Создание и заполнение ячейки + /// + void InsertTextIntoCell(int rowIndex, int columnIndex, PdfCellParameters cellParameters); + /// + /// Создание и заполнение ячейки + /// + void MergeCells(PdfCellsMergeParameters parameters); + /// + /// Создание и заполнение круговой диаграммы + /// + void CreatePieChart(IPdfPieChartParameters parameters); + /// + /// Сохранение файла + /// + void SavePdf(IPdfInfo info); + } +} diff --git a/ComponentLibrary1/office_package/Implements/SaveToPdf.cs b/ComponentLibrary1/office_package/Implements/SaveToPdf.cs new file mode 100644 index 0000000..998d435 --- /dev/null +++ b/ComponentLibrary1/office_package/Implements/SaveToPdf.cs @@ -0,0 +1,273 @@ +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using MigraDoc.DocumentObjectModel; +using MigraDoc.Rendering; +using MigraDoc.DocumentObjectModel.Tables; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Security.Cryptography; +using System.Reflection; +using System.Data.Common; +using MigraDoc.DocumentObjectModel.Shapes; +using MigraDoc.DocumentObjectModel.Shapes.Charts; + +namespace ComponentLibrary1.office_package.Implements +{ + public class SaveToPdf : ISaveToPdf + { + private Document? _document; + private Section? _section; + private Table? _table; + + #region константы + private readonly Unit BORDER_WIDTH = 0.5; + private readonly Unit COLUMN_WIDTH = Unit.FromCentimeter(3.5); + private readonly Unit IMAGE_WIDTH = Unit.FromCentimeter(15); + #endregion + + #region работа с файлом + public void CreatePdf(IPdfInfo info) + { + _document = new Document(); + DefineStyles(_document); + _section = _document.AddSection(); + } + public void SavePdf(IPdfInfo info) + { + if (string.IsNullOrWhiteSpace(info.FileName)) + { + throw new ArgumentNullException("Имя файла не задано"); + } + + if (_document == null || _section == null) + { + throw new ArgumentNullException("Документ не сформирован, сохранять нечего"); + } + var renderer = new PdfDocumentRenderer(true) + { + Document = _document + }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(info.FileName); + } + #endregion + + #region работа с текстом + private static ParagraphAlignment GetParagraphAlignment( + PdfParagraphAlignmentType type) + { + return type switch + { + PdfParagraphAlignmentType.Center => ParagraphAlignment.Center, + PdfParagraphAlignmentType.Left => ParagraphAlignment.Left, + PdfParagraphAlignmentType.Right => ParagraphAlignment.Right, + _ => ParagraphAlignment.Justify, + }; + } + + private static void DefineStyles(Document document) + { + var style = document.Styles["Normal"]; + style.Font.Name = "Times New Roman"; + style.Font.Size = 14; + style = document.Styles.AddStyle("NormalTitle", "Normal"); + style.Font.Bold = true; + } + + public void CreateParagraph(PdfParagraph pdfParagraph) + { + if (_document == null) + { + return; + } + if (_section == null) + { + _section = _document.AddSection(); + } + var paragraph = _section.AddParagraph(pdfParagraph.Text); + paragraph.Format.SpaceAfter = "1cm"; + paragraph.Format.Alignment = GetParagraphAlignment(pdfParagraph.ParagraphAlignment); + paragraph.Style = pdfParagraph.Style; + } + #endregion + + #region работа с изображениями + public void CreateImage(byte[] image) + { + if (image == null || image.Length == 0) + { + throw new ArgumentNullException("Картинка не загружена"); + } + if (_document == null) + { + return; + } + if (_section == null) + { + _section = _document.AddSection(); + } + var imageFileName = Path.GetTempFileName(); + File.WriteAllBytes(imageFileName, image); + var img = _section.AddImage(imageFileName); + img.Width = IMAGE_WIDTH; + img.LockAspectRatio = true; + _section.AddParagraph(); + } + #endregion + + #region работа с таблицами + public void CreateTable() + { + if (_document == null || _section == null) + { + return; + } + _table = _section.AddTable(); + } + + public void CreateTableWithColumns(List columns) + { + if (_document == null || _section == null) + { + return; + } + _table = _section.AddTable(); + foreach (var elem in columns) + { + _table.AddColumn(elem); + } + } + + public void CreateTableWithColumns(int columnNumber) + { + if (_document == null || _section == null) + { + return; + } + _table = _section.AddTable(); + for (int i = 0; i < columnNumber; i++) + { + _table.AddColumn(COLUMN_WIDTH); + } + } + + public void CreateRow(PdfRowParameters rowParameters) + { + if (_table == null) + { + return; + } + var row = _table.AddRow(); + for (int i = 0; i < rowParameters.Texts.Count; ++i) + { + if (!string.IsNullOrWhiteSpace(rowParameters.Texts[i])) + InsertTextIntoCell(row.Index, i, rowParameters, rowParameters.Texts[i]); + } + } + + public void InsertTextIntoColumn(PdfColumnParameters columnParameters) + { + if (_table == null) + { + return; + } + for (int i = 0; i < columnParameters.Texts.Count; ++i) + { + if (!string.IsNullOrWhiteSpace(columnParameters.Texts[i])) + InsertTextIntoCell(i, columnParameters.ColumnIndex, columnParameters, columnParameters.Texts[i]); + } + } + + public void InsertTextIntoCell(int rowIndex, int columnIndex, PdfCellParameters cellParameters) + { + InsertTextIntoCell(rowIndex, columnIndex, cellParameters, cellParameters.Text); + } + + private void InsertTextIntoCell(int rowIndex, int columnIndex, ITableTextParameters parameters, string text) + { + if (_table == null) + { + return; + } + Cell cell = _table.Rows[rowIndex].Cells[columnIndex]; + cell.AddParagraph(text); + if (!string.IsNullOrEmpty(parameters.Style)) + { + cell.Style = parameters.Style; + } + cell.Borders.Left.Width = BORDER_WIDTH; + cell.Borders.Right.Width = BORDER_WIDTH; + cell.Borders.Top.Width = BORDER_WIDTH; + cell.Borders.Bottom.Width = BORDER_WIDTH; + cell.Format.Alignment = GetParagraphAlignment( + parameters.ParagraphAlignment); + cell.VerticalAlignment = VerticalAlignment.Center; + } + + public void MergeCells(PdfCellsMergeParameters parameters) + { + if (_table == null) + { + return; + } + Cell cell = _table.Rows[parameters.RowIndex].Cells[parameters.ColumnIndex]; + switch (parameters.Direction) + { + case PdfCellsMergeDirections.Down: + cell.MergeDown = parameters.CellNumber; + break; + case PdfCellsMergeDirections.Right: + cell.MergeRight = parameters.CellNumber; + break; + } + } + #endregion + + #region работа с диаграммами + public void CreatePieChart(IPdfPieChartParameters parameters) + { + if (_document == null || _section == null) + throw new ArgumentNullException(nameof(_document), "Document is not created."); + Chart chart = new Chart(ChartType.Pie2D); + Series series = chart.SeriesCollection.AddSeries(); + series.Name = parameters.Series.SeriesName; + series.Add(parameters.Series.Data.Select(x => x.Value).ToArray()); + chart.XValues.AddXSeries().Add(parameters.Series.Data.Select(x => x.Key).ToArray()); + ConfigChart(parameters, chart); + _section.Add(chart); + } + + private void ConfigChart(IPdfPieChartParameters parameters, Chart chart) + { + chart.DataLabel.Type = DataLabelType.Percent; + chart.DataLabel.Position = DataLabelPosition.OutsideEnd; + chart.Width = Unit.FromCentimeter(16.0); + chart.Height = Unit.FromCentimeter(12.0); + chart.TopArea.AddParagraph(parameters.ChartTitle); + chart.XAxis.MajorTickMark = (TickMarkType)2; + chart.YAxis.MajorTickMark = (TickMarkType)2; + chart.YAxis.HasMajorGridlines = true; + chart.PlotArea.LineFormat.Width = new Unit(1); + chart.PlotArea.LineFormat.Visible = true; + switch (parameters.LegendLocation) + { + case PdfDiagramLegendLocation.Left: + chart.LeftArea.AddLegend(); + break; + case PdfDiagramLegendLocation.Right: + chart.RightArea.AddLegend(); + break; + case PdfDiagramLegendLocation.Top: + chart.TopArea.AddLegend(); + break; + case PdfDiagramLegendLocation.Bottom: + chart.BottomArea.AddLegend(); + break; + } + } + #endregion + } +} diff --git a/ComponentLibrary1/pdf_diagram/PdfDiagram.Designer.cs b/ComponentLibrary1/pdf_diagram/PdfDiagram.Designer.cs new file mode 100644 index 0000000..f7eac84 --- /dev/null +++ b/ComponentLibrary1/pdf_diagram/PdfDiagram.Designer.cs @@ -0,0 +1,36 @@ +namespace ComponentLibrary1.pdf_diagram +{ + partial class PdfDiagram + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором компонентов + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/ComponentLibrary1/pdf_diagram/PdfDiagram.cs b/ComponentLibrary1/pdf_diagram/PdfDiagram.cs new file mode 100644 index 0000000..96542c2 --- /dev/null +++ b/ComponentLibrary1/pdf_diagram/PdfDiagram.cs @@ -0,0 +1,45 @@ +using ComponentLibrary1.office_package; +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using ComponentLibrary1.office_package.Implements; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_diagram +{ + public partial class PdfDiagram : Component + { + ISaveToPdf SaveToPdf = new SaveToPdf(); + + public PdfDiagram() + { + InitializeComponent(); + } + + public PdfDiagram(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + + public void CreateDiagram(PdfDiagramInfo info) + { + info.CheckFields(); + SaveToPdf.CreatePdf(info); + SaveToPdf.CreateParagraph(new PdfParagraph + { + Text = info.Title, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + SaveToPdf.CreatePieChart(info); + SaveToPdf.SavePdf(info); + } + } +} diff --git a/ComponentLibrary1/pdf_diagram/PdfDiagramInfo.cs b/ComponentLibrary1/pdf_diagram/PdfDiagramInfo.cs new file mode 100644 index 0000000..7e164ae --- /dev/null +++ b/ComponentLibrary1/pdf_diagram/PdfDiagramInfo.cs @@ -0,0 +1,29 @@ +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_diagram +{ + public class PdfDiagramInfo : IPdfInfo, IPdfPieChartParameters + { + public string FileName { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public string ChartTitle { get; set; } = string.Empty; + public PdfDiagramLegendLocation LegendLocation { get; set; } = PdfDiagramLegendLocation.Right; + public PdfDiagramSeries Series { get; set; } = new(); + + public void CheckFields() + { + if (string.IsNullOrEmpty(FileName)) + throw new ArgumentNullException(nameof(FileName), "File path and name cannot be null or empty."); + if (string.IsNullOrEmpty(Title)) + throw new ArgumentNullException(nameof(Title), "Title cannot be null or empty."); + if (Series == null) + throw new ArgumentNullException(nameof(Series), "Series cannot be null or empty."); + } + } +} diff --git a/ComponentLibrary1/pdf_image/PdfImage.Designer.cs b/ComponentLibrary1/pdf_image/PdfImage.Designer.cs new file mode 100644 index 0000000..d725adf --- /dev/null +++ b/ComponentLibrary1/pdf_image/PdfImage.Designer.cs @@ -0,0 +1,36 @@ +namespace ComponentLibrary1.pdf_image +{ + partial class PdfImage + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором компонентов + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/ComponentLibrary1/pdf_image/PdfImage.cs b/ComponentLibrary1/pdf_image/PdfImage.cs new file mode 100644 index 0000000..e5099f1 --- /dev/null +++ b/ComponentLibrary1/pdf_image/PdfImage.cs @@ -0,0 +1,47 @@ +using ComponentLibrary1.office_package; +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using ComponentLibrary1.office_package.Implements; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_image +{ + public partial class PdfImage : Component + { + ISaveToPdf SaveToPdf = new SaveToPdf(); + + public PdfImage() + { + InitializeComponent(); + } + + public PdfImage(IContainer container) + { + container.Add(this); + InitializeComponent(); + } + + public void CreatePdf(PdfImageInfo info) + { + info.CheckFields(); + SaveToPdf.CreatePdf(info); + SaveToPdf.CreateParagraph(new PdfParagraph + { + Text = info.Title, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + foreach (var image in info.Images) + { + SaveToPdf.CreateImage(image); + } + SaveToPdf.SavePdf(info); + } + } +} diff --git a/ComponentLibrary1/pdf_image/PdfImageInfo.cs b/ComponentLibrary1/pdf_image/PdfImageInfo.cs new file mode 100644 index 0000000..eefaa84 --- /dev/null +++ b/ComponentLibrary1/pdf_image/PdfImageInfo.cs @@ -0,0 +1,24 @@ +using ComponentLibrary1.office_package.HelperModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_image +{ + public class PdfImageInfo : IPdfInfo + { + public string FileName { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public List Images { get; set; } = new List(); + + public void CheckFields() + { + if (string.IsNullOrWhiteSpace(FileName) || string.IsNullOrWhiteSpace(Title) || Images == null || Images.Count == 0) + { + throw new ArgumentException("Все поля должны быть заполнены."); + } + } + } +} diff --git a/ComponentLibrary1/pdf_table/PdfTable.Designer.cs b/ComponentLibrary1/pdf_table/PdfTable.Designer.cs new file mode 100644 index 0000000..afcb47c --- /dev/null +++ b/ComponentLibrary1/pdf_table/PdfTable.Designer.cs @@ -0,0 +1,36 @@ +namespace ComponentLibrary1.pdf_table +{ + partial class PdfTable + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором компонентов + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + } + + #endregion + } +} diff --git a/ComponentLibrary1/pdf_table/PdfTable.cs b/ComponentLibrary1/pdf_table/PdfTable.cs new file mode 100644 index 0000000..ec2fa06 --- /dev/null +++ b/ComponentLibrary1/pdf_table/PdfTable.cs @@ -0,0 +1,152 @@ +using ComponentLibrary1.office_package; +using ComponentLibrary1.office_package.HelperEnums; +using ComponentLibrary1.office_package.HelperModels; +using ComponentLibrary1.office_package.Implements; +using MigraDoc.DocumentObjectModel; +using MigraDoc.Rendering; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_table +{ + public partial class PdfTable : Component + { + ISaveToPdf SaveToPdf = new SaveToPdf(); + + public PdfTable() + { + InitializeComponent(); + } + + public PdfTable(IContainer container) + { + container.Add(this); + + InitializeComponent(); + } + public void CreatePdf(PdfTableInfo info) + { + info.CheckFields(); + SaveToPdf.CreatePdf(info); + SaveToPdf.CreateParagraph(new PdfParagraph + { + Text = info.Title, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + SaveToPdf.CreateTableWithColumns(info.Data.Count + 2); + SaveToPdf.CreateRow(new PdfRowParameters()); + int rowIndex = 0; + int columnIndex = 0; + List properties = new List(); + string? header; + foreach (var node in info.Headers) + { + if (string.IsNullOrWhiteSpace(node.Text)) + { + throw new Exception("Cannot read header"); + } + SaveToPdf.CreateRow(new PdfRowParameters()); + SaveToPdf.InsertTextIntoCell( + rowIndex, + columnIndex, + new PdfCellParameters + { + Text = node.Text, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Center + }); + if (node.Nodes.Count == 0) + { + SaveToPdf.MergeCells(new PdfCellsMergeParameters + { + RowIndex = rowIndex, + ColumnIndex = columnIndex, + Direction = PdfCellsMergeDirections.Right + }); + header = node.Tag as string; + if (header == null) + { + throw new Exception("Cannot read property name"); + } + properties.Add(header); + rowIndex++; + } + else + { + int mergeRowIndex = rowIndex; + int mergeColumnIndex = columnIndex; + foreach (TreeNode child in node.Nodes) + { + if (string.IsNullOrWhiteSpace(child.Text)) + { + throw new Exception("Cannot read header"); + } + SaveToPdf.CreateRow(new PdfRowParameters()); + SaveToPdf.InsertTextIntoCell( + rowIndex, + columnIndex + 1, + new PdfCellParameters + { + Text = child.Text, + Style = "NormalTitle", + ParagraphAlignment = PdfParagraphAlignmentType.Left + }); + header = child.Tag as string; + if (header == null) + { + throw new Exception("Cannot read property name"); + } + properties.Add(header); + rowIndex++; + } + SaveToPdf.MergeCells(new PdfCellsMergeParameters + { + RowIndex = mergeRowIndex, + ColumnIndex = mergeColumnIndex, + Direction = PdfCellsMergeDirections.Down, + CellNumber = node.Nodes.Count - 1 + }); + } + } + columnIndex = 2; + foreach (var obj in info.Data) + { + if (obj == null) + { + throw new Exception("Table Data element cannot be null"); + } + List cells = new List(); + for (int i = 0; i < properties.Count; i++) + { + string propertyName = properties[i]; + var property = obj.GetType().GetProperty(propertyName); + if (property is null) + { + throw new ArgumentException($"Failed to find property {propertyName} in provided objects class"); + } + var value = property.GetValue(obj)?.ToString(); + if (value == null) + { + throw new ArgumentException($"Failed to find property {propertyName} in provided objects class"); + } + cells.Add(value); + } + SaveToPdf.InsertTextIntoColumn(new PdfColumnParameters + { + Texts = cells, + ColumnIndex = columnIndex, + Style = "Normal", + ParagraphAlignment= PdfParagraphAlignmentType.Left + }); + columnIndex++; + } + SaveToPdf.SavePdf(info); + } + } +} diff --git a/ComponentLibrary1/pdf_table/PdfTableInfo.cs b/ComponentLibrary1/pdf_table/PdfTableInfo.cs new file mode 100644 index 0000000..b7ebe94 --- /dev/null +++ b/ComponentLibrary1/pdf_table/PdfTableInfo.cs @@ -0,0 +1,29 @@ +using ComponentLibrary1.office_package.HelperModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ComponentLibrary1.pdf_table +{ + public class PdfTableInfo : IPdfInfo + { + public string FileName { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public List Headers { get; set; } = new(); + public List Data { get; set; } = new(); + + public void CheckFields() + { + if (string.IsNullOrWhiteSpace(FileName)) + throw new ArgumentException("Имя файла не может быть пустым.", nameof(FileName)); + if (string.IsNullOrWhiteSpace(Title)) + throw new ArgumentException("Название документа не может быть пустым.", nameof(Title)); + if (Headers == null || Headers.Count == 0) + throw new ArgumentException("Заголовки для шапки не могут быть пустыми.", nameof(Headers)); + if (Data == null || Data.Count == 0) + throw new ArgumentException("Данные для таблицы не могут быть пустыми.", nameof(Data)); + } + } +} diff --git a/TestApp1/Form1.Designer.cs b/TestApp1/Form1.Designer.cs index 07c705d..b2b849d 100644 --- a/TestApp1/Form1.Designer.cs +++ b/TestApp1/Form1.Designer.cs @@ -28,6 +28,7 @@ /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); input = new Button(); clear = new Button(); textBox1 = new TextBox(); @@ -55,11 +56,25 @@ clearTreeList = new Button(); textBoxFullName = new TextBox(); getObject = new Button(); + groupBox4 = new GroupBox(); + listBoxImages = new ListBox(); + chooseImage = new Button(); + createPdfImages = new Button(); + pdfImage = new ComponentLibrary1.pdf_image.PdfImage(components); + groupBox5 = new GroupBox(); + createTable = new Button(); + pdfTable = new ComponentLibrary1.pdf_table.PdfTable(components); + pdfDiagram = new ComponentLibrary1.pdf_diagram.PdfDiagram(components); + groupBox6 = new GroupBox(); + createDiagram = new Button(); groupBox1.SuspendLayout(); groupBox2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)numericMax).BeginInit(); ((System.ComponentModel.ISupportInitialize)numericMin).BeginInit(); groupBox3.SuspendLayout(); + groupBox4.SuspendLayout(); + groupBox5.SuspendLayout(); + groupBox6.SuspendLayout(); SuspendLayout(); // // input @@ -187,7 +202,7 @@ // // inputMin // - inputMin.Location = new Point(7, 301); + inputMin.Location = new Point(6, 301); inputMin.Name = "inputMin"; inputMin.Size = new Size(70, 26); inputMin.TabIndex = 8; @@ -262,28 +277,28 @@ // textBoxOutput.Location = new Point(6, 240); textBoxOutput.Name = "textBoxOutput"; - textBoxOutput.Size = new Size(146, 23); + textBoxOutput.Size = new Size(145, 23); textBoxOutput.TabIndex = 15; // // treeList // treeList.Location = new Point(6, 22); treeList.Name = "treeList"; - treeList.Size = new Size(146, 125); + treeList.Size = new Size(145, 125); treeList.TabIndex = 14; // // textBoxDepartment // textBoxDepartment.Location = new Point(6, 153); textBoxDepartment.Name = "textBoxDepartment"; - textBoxDepartment.Size = new Size(146, 23); + textBoxDepartment.Size = new Size(145, 23); textBoxDepartment.TabIndex = 13; // // textBoxJobTitle // textBoxJobTitle.Location = new Point(6, 182); textBoxJobTitle.Name = "textBoxJobTitle"; - textBoxJobTitle.Size = new Size(146, 23); + textBoxJobTitle.Size = new Size(145, 23); textBoxJobTitle.TabIndex = 12; // // add @@ -310,7 +325,7 @@ // textBoxFullName.Location = new Point(6, 211); textBoxFullName.Name = "textBoxFullName"; - textBoxFullName.Size = new Size(146, 23); + textBoxFullName.Size = new Size(145, 23); textBoxFullName.TabIndex = 2; // // getObject @@ -323,11 +338,95 @@ getObject.UseVisualStyleBackColor = true; getObject.Click += getObject_Click; // + // groupBox4 + // + groupBox4.Controls.Add(listBoxImages); + groupBox4.Controls.Add(chooseImage); + groupBox4.Controls.Add(createPdfImages); + groupBox4.Location = new Point(505, 12); + groupBox4.Name = "groupBox4"; + groupBox4.Size = new Size(157, 205); + groupBox4.TabIndex = 11; + groupBox4.TabStop = false; + groupBox4.Text = "Test4"; + // + // listBoxImages + // + listBoxImages.FormattingEnabled = true; + listBoxImages.ItemHeight = 15; + listBoxImages.Location = new Point(6, 23); + listBoxImages.Name = "listBoxImages"; + listBoxImages.Size = new Size(146, 109); + listBoxImages.TabIndex = 3; + // + // chooseImage + // + chooseImage.Location = new Point(6, 141); + chooseImage.Name = "chooseImage"; + chooseImage.Size = new Size(146, 26); + chooseImage.TabIndex = 0; + chooseImage.Text = "Выбрать изображения"; + chooseImage.UseVisualStyleBackColor = true; + chooseImage.Click += chooseImage_Click; + // + // createPdfImages + // + createPdfImages.Location = new Point(6, 173); + createPdfImages.Name = "createPdfImages"; + createPdfImages.Size = new Size(146, 26); + createPdfImages.TabIndex = 1; + createPdfImages.Text = "Cоздать pdf с фотками"; + createPdfImages.UseVisualStyleBackColor = true; + createPdfImages.Click += createPdfImages_Click; + // + // groupBox5 + // + groupBox5.Controls.Add(createTable); + groupBox5.Location = new Point(505, 223); + groupBox5.Name = "groupBox5"; + groupBox5.Size = new Size(157, 59); + groupBox5.TabIndex = 12; + groupBox5.TabStop = false; + groupBox5.Text = "Test5"; + // + // createTable + // + createTable.Location = new Point(6, 23); + createTable.Name = "createTable"; + createTable.Size = new Size(146, 26); + createTable.TabIndex = 0; + createTable.Text = "Создать pdf таблицу"; + createTable.UseVisualStyleBackColor = true; + createTable.Click += createTable_Click; + // + // groupBox6 + // + groupBox6.Controls.Add(createDiagram); + groupBox6.Location = new Point(505, 285); + groupBox6.Name = "groupBox6"; + groupBox6.Size = new Size(157, 59); + groupBox6.TabIndex = 13; + groupBox6.TabStop = false; + groupBox6.Text = "Test6"; + // + // createDiagram + // + createDiagram.Location = new Point(6, 23); + createDiagram.Name = "createDiagram"; + createDiagram.Size = new Size(146, 26); + createDiagram.TabIndex = 0; + createDiagram.Text = "Создать pdf диаграмму"; + createDiagram.UseVisualStyleBackColor = true; + createDiagram.Click += createDiagram_Click; + // // Form1 // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(518, 357); + ClientSize = new Size(676, 360); + Controls.Add(groupBox6); + Controls.Add(groupBox5); + Controls.Add(groupBox4); Controls.Add(groupBox3); Controls.Add(groupBox2); Controls.Add(groupBox1); @@ -341,6 +440,9 @@ ((System.ComponentModel.ISupportInitialize)numericMin).EndInit(); groupBox3.ResumeLayout(false); groupBox3.PerformLayout(); + groupBox4.ResumeLayout(false); + groupBox5.ResumeLayout(false); + groupBox6.ResumeLayout(false); ResumeLayout(false); } @@ -373,5 +475,16 @@ private TextBox textBoxJobTitle; private ComponentLibrary1.tree_list.TreeList treeList; private TextBox textBoxOutput; + private GroupBox groupBox4; + private Button chooseImage; + private Button createPdfImages; + private ListBox listBoxImages; + private ComponentLibrary1.pdf_image.PdfImage pdfImage; + private GroupBox groupBox5; + private Button createTable; + private ComponentLibrary1.pdf_table.PdfTable pdfTable; + private ComponentLibrary1.pdf_diagram.PdfDiagram pdfDiagram; + private GroupBox groupBox6; + private Button createDiagram; } } diff --git a/TestApp1/Form1.cs b/TestApp1/Form1.cs index 7bddb7b..9a4b739 100644 --- a/TestApp1/Form1.cs +++ b/TestApp1/Form1.cs @@ -1,16 +1,24 @@ +using ComponentLibrary1.pdf_diagram; +using ComponentLibrary1.pdf_image; +using ComponentLibrary1.pdf_table; + namespace TestApp1 { public partial class Form1 : Form { + private List selectedImages = new List(); public Form1() { InitializeComponent(); + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); checkList.ChangeEvent += DoChange; limitedText.ChangeEvent += DoChange2; - List categories = new List(); - categories.Add("Department"); - categories.Add("JobTitle"); - categories.Add("FullName"); + List categories = new List + { + "Department", + "JobTitle", + "FullName" + }; treeList.SetCategories(categories); } @@ -132,5 +140,139 @@ namespace TestApp1 } } #endregion + + #region test4 + private void chooseImage_Click(object sender, EventArgs e) + { + try + { + using OpenFileDialog openFileDialog = new OpenFileDialog + { + Multiselect = true, + Filter = "|*.jpg;*.jpeg;*.png;*.bmp" + }; + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + selectedImages.Clear(); + listBoxImages.Items.Clear(); + foreach (string filePath in openFileDialog.FileNames) + { + selectedImages.Add(File.ReadAllBytes(filePath)); + listBoxImages.Items.Add(Path.GetFileName(filePath)); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + + private void createPdfImages_Click(object sender, EventArgs e) + { + try + { + if (selectedImages.Count == 0) + { + MessageBox.Show(" !", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + var info = new PdfImageInfo + { + FileName = "C://Users//user//PdfWithImage.pdf", + Title = "", + Images = selectedImages + }; + pdfImage.CreatePdf(info); + MessageBox.Show("PDF !", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + #endregion + + #region test5 + private void createTable_Click(object sender, EventArgs e) + { + try + { + List headers = new List + { + new TreeNode + { + Text = "", + Tag = "FullName", + }, + new TreeNode(" ", new TreeNode[] + { + new TreeNode + { + Text = "", + Tag = "Department" + }, + new TreeNode + { + Text = "", + Tag = "JobTitle" + } + }) + }; + List data = new List + { + new Employee(" ", " ", ""), + new Employee(" ", "", ""), + new Employee(" ", "", "") + }; + var info = new PdfTableInfo + { + FileName = "C://Users//user//PdfWithTable.pdf", + Title = "", + Headers = headers, + Data = data + }; + pdfTable.CreatePdf(info); + MessageBox.Show("PDF !", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + #endregion + + #region test6 + private void createDiagram_Click(object sender, EventArgs e) + { + try + { + pdfDiagram.CreateDiagram(new PdfDiagramInfo + { + FileName = "C://Users//user//PdfWithPieDiagram.pdf", + Title = " ", + ChartTitle = " , 2024", + LegendLocation = ComponentLibrary1.office_package.HelperEnums.PdfDiagramLegendLocation.Bottom, + Series = new ComponentLibrary1.office_package.HelperModels.PdfDiagramSeries + { + SeriesName = "DesctopOperatingSystemAugust2024", + Data = new Dictionary + { + { "Windows", 71.5 }, + { "OS X", 15.5 }, + { "Linux", 4.5 }, + { "Others", 8.5 }, + } + } + }); + MessageBox.Show("PDF !", ""); + } + catch (Exception ex) + { + MessageBox.Show($": {ex.Message}"); + } + } + #endregion } } diff --git a/TestApp1/Form1.resx b/TestApp1/Form1.resx index af32865..3b2f672 100644 --- a/TestApp1/Form1.resx +++ b/TestApp1/Form1.resx @@ -117,4 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + + + 122, 17 + + + 221, 17 + \ No newline at end of file