From 2faa7bf7f9f6ae5c7959e79e51bd7c207dcd9796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC=D0=B8=D1=80=20=D0=94?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=BB=D0=BE=D0=B2?= Date: Wed, 30 Oct 2024 14:26:40 +0400 Subject: [PATCH] =?UTF-8?q?=D0=93=D0=BE=D1=82=D0=BE=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Components/Components.csproj | 3 + Components/NonVisual/HeaderedTablePDF.cs | 35 ++++--- Components/NonVisual/HistogramPDF.cs | 98 ++++++++++++++++++- Components/NonVisual/TablePDF.cs | 1 + Components/SaveToPdfHelpers/HistogramData.cs | 17 ++++ .../SaveToPdfHelpers/PDFTableSettings.cs | 4 +- WinFormsTest/Form1.Designer.cs | 49 +++++++++- WinFormsTest/Form1.cs | 93 ++++++++++++++++++ WinFormsTest/Form1.resx | 9 ++ 9 files changed, 287 insertions(+), 22 deletions(-) create mode 100644 Components/SaveToPdfHelpers/HistogramData.cs diff --git a/Components/Components.csproj b/Components/Components.csproj index 7fbd9ef..8a64cb8 100644 --- a/Components/Components.csproj +++ b/Components/Components.csproj @@ -8,6 +8,9 @@ + + + diff --git a/Components/NonVisual/HeaderedTablePDF.cs b/Components/NonVisual/HeaderedTablePDF.cs index 3bb6343..696ae6a 100644 --- a/Components/NonVisual/HeaderedTablePDF.cs +++ b/Components/NonVisual/HeaderedTablePDF.cs @@ -24,6 +24,7 @@ namespace Components.NonVisual public HeaderedTablePDF(IContainer container) { container.Add(this); + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); InitializeComponent(); } @@ -33,10 +34,14 @@ namespace Components.NonVisual if (settings == null || string.IsNullOrEmpty(settings.FilePath) || string.IsNullOrEmpty(settings.DocumentTitle) || - settings.Columns == null || settings.Columns.Count == 0 || - settings.DataList == null) + settings.HeaderTitles == null || settings.HeaderTitles.Count == 0 || + settings.ColumnWidths == null || settings.DataList == null || + settings.ColumnPropertyMappings == null) throw new ArgumentException("Заполнены не все необходимые данные для генерации документа."); + if (settings.HeaderTitles.Count != settings.ColumnWidths.Count) + throw new ArgumentException("Количество заголовков должно совпадать с количеством ширин столбцов."); + Document document = new Document(); Section section = document.AddSection(); section.AddParagraph(settings.DocumentTitle, "Heading1"); @@ -45,9 +50,9 @@ namespace Components.NonVisual table.Borders.Width = 0.75; // столбцы - foreach (var (_, width, _, _) in settings.Columns) + for (int i = 0; i < settings.ColumnWidths.Count; i++) { - Column column = table.AddColumn(Unit.FromCentimeter(width)); + Column column = table.AddColumn(Unit.FromCentimeter(settings.ColumnWidths[i])); column.Format.Alignment = ParagraphAlignment.Center; } @@ -55,12 +60,11 @@ namespace Components.NonVisual Row headerRow = table.AddRow(); headerRow.Height = Unit.FromCentimeter(settings.HeaderRowHeight); - for (int columnIndex = 0; columnIndex < settings.Columns.Count; columnIndex++) + for (int i = 0; i < settings.HeaderTitles.Count; i++) { - var (headerTitle, _, _, _) = settings.Columns[columnIndex]; - headerRow.Cells[columnIndex].AddParagraph(headerTitle); - headerRow.Cells[columnIndex].Format.Font.Bold = true; - headerRow.Cells[columnIndex].Format.Alignment = ParagraphAlignment.Center; + headerRow.Cells[i].AddParagraph(settings.HeaderTitles[i]); + headerRow.Cells[i].Format.Font.Bold = true; + headerRow.Cells[i].Format.Alignment = ParagraphAlignment.Center; } // данные @@ -69,20 +73,15 @@ namespace Components.NonVisual Row row = table.AddRow(); row.Height = Unit.FromCentimeter(settings.DataRowHeight); - for (int columnIndex = 0; columnIndex < settings.Columns.Count; columnIndex++) + foreach (var columnMapping in settings.ColumnPropertyMappings) { - var (_, _, propertyName, _) = settings.Columns[columnIndex]; + PropertyInfo propertyInfo = typeof(T).GetProperty(columnMapping.Value); - PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName); if (propertyInfo == null) - throw new ArgumentException($"Свойство {propertyName} не найдено в классе {typeof(T).Name}."); + throw new ArgumentException($"Свойство {columnMapping.Value} не найдено в классе {typeof(T).Name}."); object value = propertyInfo.GetValue(dataItem); - if (columnIndex == 0) - { - row.Cells[columnIndex].Format.Font.Bold = true; - } - row.Cells[columnIndex].AddParagraph(value != null ? value.ToString() : ""); + row.Cells[columnMapping.Key].AddParagraph(value != null ? value.ToString() : ""); } } diff --git a/Components/NonVisual/HistogramPDF.cs b/Components/NonVisual/HistogramPDF.cs index 454a8e9..7e76193 100644 --- a/Components/NonVisual/HistogramPDF.cs +++ b/Components/NonVisual/HistogramPDF.cs @@ -1,10 +1,17 @@ -using System; +using Components.SaveToPdfHelpers; +using MigraDoc.DocumentObjectModel; +using MigraDoc.Rendering; +using OxyPlot.Series; +using OxyPlot; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using OxyPlot.WindowsForms; +using OxyPlot.Legends; namespace Components.NonVisual { @@ -13,13 +20,100 @@ namespace Components.NonVisual public HistogramPDF() { InitializeComponent(); + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); } - public HistogramPDF(IContainer container) { container.Add(this); InitializeComponent(); } + + public void CreateHistogramPdf(HistogramData histogramData) + { + if (string.IsNullOrEmpty(histogramData.filePath)) + throw new ArgumentException("Путь к файлу не может быть пустым."); + if (string.IsNullOrEmpty(histogramData.documentTitle)) + throw new ArgumentException("Название документа не может быть пустым."); + if (string.IsNullOrEmpty(histogramData.chartTitle)) + throw new ArgumentException("Заголовок диаграммы не может быть пустым."); + if (histogramData.chartData == null || histogramData.chartData.Count == 0) + throw new ArgumentException("Набор данных не может быть пустым."); + + foreach (var data in histogramData.chartData) + { + if (string.IsNullOrEmpty(data.SeriesName) || data.Data == null || data.Data.Count == 0) + throw new ArgumentException($"Набор данных для серии '{data.SeriesName}' некорректен."); + } + + // создание графика + var plotModel = new PlotModel { Title = histogramData.chartTitle }; + + foreach (var data in histogramData.chartData) + { + var barSeries = new BarSeries { Title = data.SeriesName }; + foreach (var item in data.Data) + { + barSeries.Items.Add(new BarItem(item.Value)); + } + plotModel.Series.Add(barSeries); + } + + // Добавление легенды + AddLegend(plotModel, histogramData.legendPosition); + + // сохранение графика в изображение + var pngExporter = new PngExporter { Width = 600, Height = 400 }; + using (var stream = new MemoryStream()) + { + pngExporter.Export(plotModel, stream); + File.WriteAllBytes("chart.png", stream.ToArray()); + } + + // создание документа + Document document = new Document(); + document.Info.Title = histogramData.documentTitle; + document.Info.Subject = "Гистограмма"; + + Section section = document.AddSection(); + section.AddParagraph(histogramData.chartTitle, "Heading1"); + + // вставка изображения в PDF + var image = section.AddImage("chart.png"); + image.Width = Unit.FromCentimeter(15); + + PdfDocumentRenderer renderer = new PdfDocumentRenderer(true) { Document = document }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(histogramData.filePath); + + File.Delete("chart.png"); + } + + //добавление легенды + private void AddLegend(PlotModel plotModel, LegendPositions legendPosition) + { + // Создание легенды + var legend = new OxyPlot.Legends.Legend + { + LegendPlacement = LegendPlacement.Outside, + LegendPosition = ConvertLegendPosition(legendPosition), + LegendOrientation = LegendOrientation.Vertical + }; + + plotModel.Legends.Add(legend); + } + + // конвертация позиции легенды + private OxyPlot.Legends.LegendPosition ConvertLegendPosition(LegendPositions legendPosition) + { + return legendPosition switch + { + LegendPositions.Top => OxyPlot.Legends.LegendPosition.TopCenter, + LegendPositions.Bottom => OxyPlot.Legends.LegendPosition.BottomCenter, + LegendPositions.Left => OxyPlot.Legends.LegendPosition.LeftTop, + LegendPositions.Right => OxyPlot.Legends.LegendPosition.RightTop, + _ => OxyPlot.Legends.LegendPosition.TopCenter, // Положение по умолчанию + }; + } } } diff --git a/Components/NonVisual/TablePDF.cs b/Components/NonVisual/TablePDF.cs index f964a50..d7e82ee 100644 --- a/Components/NonVisual/TablePDF.cs +++ b/Components/NonVisual/TablePDF.cs @@ -24,6 +24,7 @@ namespace Components.NonVisual public TablePDF(IContainer container) { container.Add(this); + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); InitializeComponent(); } diff --git a/Components/SaveToPdfHelpers/HistogramData.cs b/Components/SaveToPdfHelpers/HistogramData.cs new file mode 100644 index 0000000..958a7b6 --- /dev/null +++ b/Components/SaveToPdfHelpers/HistogramData.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Components.SaveToPdfHelpers +{ + public class HistogramData + { + public string filePath { get; set; } = string.Empty; + public string documentTitle { get; set; } = string.Empty; + public string chartTitle { get; set; } = string.Empty; + public LegendPositions legendPosition { get; set; } + public List? chartData { get; set; } + } +} diff --git a/Components/SaveToPdfHelpers/PDFTableSettings.cs b/Components/SaveToPdfHelpers/PDFTableSettings.cs index e7ef4d7..7f97c72 100644 --- a/Components/SaveToPdfHelpers/PDFTableSettings.cs +++ b/Components/SaveToPdfHelpers/PDFTableSettings.cs @@ -10,9 +10,11 @@ namespace Components.SaveToPdfHelpers { public string FilePath { get; set; } = string.Empty; public string DocumentTitle { get; set; } = string.Empty; - public List<(string HeaderTitle, float Width, string PropertyName, int ColumnIndex)> Columns { get; set; } + public List HeaderTitles { get; set; } + public List ColumnWidths { get; set; } public float HeaderRowHeight { get; set; } public float DataRowHeight { get; set; } public List? DataList { get; set; } + public Dictionary ColumnPropertyMappings { get; set; } } } diff --git a/WinFormsTest/Form1.Designer.cs b/WinFormsTest/Form1.Designer.cs index 908c6a6..38c3f81 100644 --- a/WinFormsTest/Form1.Designer.cs +++ b/WinFormsTest/Form1.Designer.cs @@ -28,9 +28,16 @@ /// private void InitializeComponent() { + components = new System.ComponentModel.Container(); customListBox = new Components.CustomListBox(); customTextBox = new Components.CustomTextBox(); customDataGridView1 = new Components.CustomDataGridView(); + buttonCreateTable = new Button(); + buttonCreateHeaderedTable = new Button(); + buttonCreateHistogram = new Button(); + tablepdf1 = new Components.NonVisual.TablePDF(components); + histogrampdf1 = new Components.NonVisual.HistogramPDF(components); + headeredTablepdf1 = new Components.NonVisual.HeaderedTablePDF(components); SuspendLayout(); // // customListBox @@ -55,14 +62,47 @@ customDataGridView1.Size = new Size(449, 150); customDataGridView1.TabIndex = 2; // + // buttonCreateTable + // + buttonCreateTable.Location = new Point(41, 235); + buttonCreateTable.Name = "buttonCreateTable"; + buttonCreateTable.Size = new Size(139, 44); + buttonCreateTable.TabIndex = 11; + buttonCreateTable.Text = "Документ с контекстом"; + buttonCreateTable.UseVisualStyleBackColor = true; + buttonCreateTable.Click += GeneratePdfButton_Click; + // + // buttonCreateHeaderedTable + // + buttonCreateHeaderedTable.Location = new Point(204, 231); + buttonCreateHeaderedTable.Name = "buttonCreateHeaderedTable"; + buttonCreateHeaderedTable.Size = new Size(139, 53); + buttonCreateHeaderedTable.TabIndex = 12; + buttonCreateHeaderedTable.Text = "Документ с настраиваемой таблицей"; + buttonCreateHeaderedTable.UseVisualStyleBackColor = true; + buttonCreateHeaderedTable.Click += btnGeneratePDF_Click; + // + // buttonCreateHistogram + // + buttonCreateHistogram.Location = new Point(362, 235); + buttonCreateHistogram.Name = "buttonCreateHistogram"; + buttonCreateHistogram.Size = new Size(139, 44); + buttonCreateHistogram.TabIndex = 13; + buttonCreateHistogram.Text = "Документ с диаграммой"; + buttonCreateHistogram.UseVisualStyleBackColor = true; + buttonCreateHistogram.Click += btnGenerateHistogrammPdf_Click; + // // Form1 // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(1003, 257); + ClientSize = new Size(934, 296); Controls.Add(customDataGridView1); Controls.Add(customTextBox); Controls.Add(customListBox); + Controls.Add(buttonCreateTable); + Controls.Add(buttonCreateHeaderedTable); + Controls.Add(buttonCreateHistogram); Name = "Form1"; Text = "Form1"; ResumeLayout(false); @@ -73,5 +113,12 @@ private Components.CustomListBox customListBox; private Components.CustomTextBox customTextBox; private Components.CustomDataGridView customDataGridView1; + + private Button buttonCreateTable; + private Button buttonCreateHeaderedTable; + private Button buttonCreateHistogram; + private Components.NonVisual.TablePDF tablepdf1; + private Components.NonVisual.HistogramPDF histogrampdf1; + private Components.NonVisual.HeaderedTablePDF headeredTablepdf1; } } diff --git a/WinFormsTest/Form1.cs b/WinFormsTest/Form1.cs index 78cf944..0673f55 100644 --- a/WinFormsTest/Form1.cs +++ b/WinFormsTest/Form1.cs @@ -1,5 +1,8 @@ using Components; +using Components.NonVisual; using Components.Object; +using Components.SaveToPdfHelpers; +using OxyPlot.Legends; namespace WinFormsTest { @@ -42,5 +45,95 @@ namespace WinFormsTest }; customDataGridView1.FillData(data); } + + private void GeneratePdfButton_Click(object sender, EventArgs e) + { + var settings = new PdfDocumentData( + "F:\\1.pdf", + " ", + new List + { + new string[,] + { + { " 1.1", " 2.1", " 3.1" }, + { " 2.1", " 2.2", " 3.2" } + }, + new string[,] + { + { " 1", " 2" }, + { " 1", " 2" } + } + }); + try + { + tablepdf1.GeneratePdf(settings); + MessageBox.Show("PDF- !", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show($" : {ex.Message}", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + private void btnGeneratePDF_Click(object sender, EventArgs e) + { + var settings = new PDFTableSettings + { + FilePath = "F:\\2.pdf", + DocumentTitle = " ", + HeaderTitles = new List { "", "", "" }, + ColumnWidths = new List { 6.0f, 2.0f, 6.0f }, + HeaderRowHeight = 1.0f, + DataRowHeight = 1.0f, + DataList = new List + { + new Person ( " ", 30, "Alex@mail.ru" ), + new Person ( " ", 25, "221B_Baker_Street@mail.com" ), + new Person (" ", 41, "Stas@gmail.com") + }, + ColumnPropertyMappings = new Dictionary + { + { 0, nameof(Person.Name) }, + { 1, nameof(Person.Age) }, + { 2, nameof(Person.Email) } + } + }; + + try + { + headeredTablepdf1.GeneratePDFWithHead(settings); + MessageBox.Show("PDF- !", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show($": {ex.Message}"); + } + } + private void btnGenerateHistogrammPdf_Click(object sender, EventArgs e) + { + var setting = new HistogramData + { + filePath = "F:\\.pdf", + documentTitle = "", + chartTitle = " ", + legendPosition = LegendPositions.Bottom, + + chartData = new List + { + new ChartData { SeriesName = " 1", Data = new Dictionary { { " 1", 5 }, { " 2", 10 } } }, + new ChartData { SeriesName = " 2", Data = new Dictionary { { " 1", 3 }, { " 2", 8 } } }, + new ChartData { SeriesName = " 3", Data = new Dictionary { { " 1", 3 }, { " 2", 8 } } } + } + }; + try + { + + histogrampdf1.CreateHistogramPdf(setting); + MessageBox.Show("PDF !", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show($": {ex.Message}", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } } } diff --git a/WinFormsTest/Form1.resx b/WinFormsTest/Form1.resx index af32865..579de6d 100644 --- a/WinFormsTest/Form1.resx +++ b/WinFormsTest/Form1.resx @@ -117,4 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + + + 121, 17 + + + 253, 17 + \ No newline at end of file