diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..5140c11
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,304 @@
+# Удалите строку ниже, если вы хотите наследовать параметры .editorconfig из каталогов, расположенных выше в иерархии
+root = true
+
+# Файлы C#
+[*.cs]
+
+#### Основные параметры EditorConfig ####
+
+# Отступы и интервалы
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# Предпочтения для новых строк
+end_of_line = crlf
+insert_final_newline = false
+
+#### Рекомендации по написанию кода .NET ####
+
+# Упорядочение Using
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = false
+file_header_template = unset
+
+# Предпочтения для this. и Me.
+dotnet_style_qualification_for_event = false:suggestion
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+
+# Параметры использования ключевых слов языка и типов BCL
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Предпочтения для скобок
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
+
+# Предпочтения модификатора
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# Выражения уровень предпочтения
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true:warning
+dotnet_style_explicit_tuple_names = true:warning
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true:warning
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:warning
+dotnet_style_prefer_collection_expression = when_types_loosely_match
+dotnet_style_prefer_compound_assignment = true:warning
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
+dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
+dotnet_style_prefer_inferred_tuple_names = true:warning
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true
+dotnet_style_prefer_simplified_boolean_expressions = true:warning
+dotnet_style_prefer_simplified_interpolation = true
+
+# Предпочтения для полей
+dotnet_style_readonly_field = true
+
+# Настройки параметров
+dotnet_code_quality_unused_parameters = all
+
+# Параметры подавления
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# Предпочтения для новых строк
+dotnet_style_allow_multiple_blank_lines_experimental = false:warning
+dotnet_style_allow_statement_immediately_after_block_experimental = false:suggestion
+
+#### Рекомендации по написанию кода C# ####
+
+# Предпочтения var
+csharp_style_var_elsewhere = false:suggestion
+csharp_style_var_for_built_in_types = false:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+
+# Члены, заданные выражениями
+csharp_style_expression_bodied_accessors = true:warning
+csharp_style_expression_bodied_constructors = false:suggestion
+csharp_style_expression_bodied_indexers = true:warning
+csharp_style_expression_bodied_lambdas = true:warning
+csharp_style_expression_bodied_local_functions = false
+csharp_style_expression_bodied_methods = true:suggestion
+csharp_style_expression_bodied_operators = true:suggestion
+csharp_style_expression_bodied_properties = true:warning
+
+# Настройки соответствия шаблонов
+csharp_style_pattern_matching_over_as_with_null_check = true
+csharp_style_pattern_matching_over_is_with_cast_check = true
+csharp_style_prefer_extended_property_pattern = true
+csharp_style_prefer_not_pattern = true
+csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_switch_expression = true:warning
+
+# Настройки проверки на null
+csharp_style_conditional_delegate_call = true
+
+# Предпочтения модификатора
+csharp_prefer_static_local_function = true
+csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
+csharp_style_prefer_readonly_struct = true
+csharp_style_prefer_readonly_struct_member = true
+
+# Предпочтения для блоков кода
+csharp_prefer_braces = true:suggestion
+csharp_prefer_simple_using_statement = true
+csharp_style_namespace_declarations = block_scoped:warning
+csharp_style_prefer_method_group_conversion = true:warning
+csharp_style_prefer_primary_constructors = true
+csharp_style_prefer_top_level_statements = true:warning
+
+# Выражения уровень предпочтения
+csharp_prefer_simple_default_expression = true:warning
+csharp_style_deconstructed_variable_declaration = true
+csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
+csharp_style_inlined_variable_declaration = true
+csharp_style_prefer_index_operator = true:warning
+csharp_style_prefer_local_over_anonymous_function = true
+csharp_style_prefer_null_check_over_type_check = true
+csharp_style_prefer_range_operator = true:warning
+csharp_style_prefer_tuple_swap = true:warning
+csharp_style_prefer_utf8_string_literals = true
+csharp_style_throw_expression = true
+csharp_style_unused_value_assignment_preference = discard_variable:warning
+csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
+
+# предпочтения для директивы using
+csharp_using_directive_placement = outside_namespace:warning
+
+# Предпочтения для новых строк
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:warning
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false:warning
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false:warning
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:warning
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:warning
+
+#### Правила форматирования C# ####
+
+# Предпочтения для новых строк
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+# Предпочтения для отступов
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# Предпочтения для интервалов
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Предпочтения переноса
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#### Стили именования ####
+
+# Правила именования
+
+dotnet_naming_rule.asyncmethods_should_be_pascalcaseasync.severity = warning
+dotnet_naming_rule.asyncmethods_should_be_pascalcaseasync.symbols = asyncmethods
+dotnet_naming_rule.asyncmethods_should_be_pascalcaseasync.style = pascalcaseasync
+
+dotnet_naming_rule.staticasyncmethods_should_be_pascalcaseasync.severity = warning
+dotnet_naming_rule.staticasyncmethods_should_be_pascalcaseasync.symbols = staticasyncmethods
+dotnet_naming_rule.staticasyncmethods_should_be_pascalcaseasync.style = pascalcaseasync
+
+dotnet_naming_rule.constmember_should_be_constant_case.severity = warning
+dotnet_naming_rule.constmember_should_be_constant_case.symbols = constmember
+dotnet_naming_rule.constmember_should_be_constant_case.style = constant_case
+
+dotnet_naming_rule.genericparametrs_should_be_typepascalcase.severity = warning
+dotnet_naming_rule.genericparametrs_should_be_typepascalcase.symbols = genericparametrs
+dotnet_naming_rule.genericparametrs_should_be_typepascalcase.style = typepascalcase
+
+dotnet_naming_rule.localmembers_should_be_camelcase.severity = warning
+dotnet_naming_rule.localmembers_should_be_camelcase.symbols = localmembers
+dotnet_naming_rule.localmembers_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.privatfealds_should_be__privatcamalcase.severity = warning
+dotnet_naming_rule.privatfealds_should_be__privatcamalcase.symbols = privatfealds
+dotnet_naming_rule.privatfealds_should_be__privatcamalcase.style = _privatcamalcase
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = warning
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+# Спецификации символов
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+dotnet_naming_symbols.asyncmethods.applicable_kinds = method
+dotnet_naming_symbols.asyncmethods.applicable_accessibilities = *
+dotnet_naming_symbols.asyncmethods.required_modifiers = async
+
+dotnet_naming_symbols.staticasyncmethods.applicable_kinds = method, local_function
+dotnet_naming_symbols.staticasyncmethods.applicable_accessibilities = *
+dotnet_naming_symbols.staticasyncmethods.required_modifiers = async, static
+
+dotnet_naming_symbols.constmember.applicable_kinds = property, field
+dotnet_naming_symbols.constmember.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.constmember.required_modifiers = const
+
+dotnet_naming_symbols.localmembers.applicable_kinds = property, field, parameter, local, method
+dotnet_naming_symbols.localmembers.applicable_accessibilities = local
+dotnet_naming_symbols.localmembers.required_modifiers =
+
+dotnet_naming_symbols.privatfealds.applicable_kinds = property, field
+dotnet_naming_symbols.privatfealds.applicable_accessibilities = private
+dotnet_naming_symbols.privatfealds.required_modifiers =
+
+dotnet_naming_symbols.genericparametrs.applicable_kinds = type_parameter
+dotnet_naming_symbols.genericparametrs.applicable_accessibilities = *
+dotnet_naming_symbols.genericparametrs.required_modifiers =
+
+# Стили именования
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.camelcase.required_prefix =
+dotnet_naming_style.camelcase.required_suffix =
+dotnet_naming_style.camelcase.word_separator =
+dotnet_naming_style.camelcase.capitalization = camel_case
+
+dotnet_naming_style.constant_case.required_prefix =
+dotnet_naming_style.constant_case.required_suffix =
+dotnet_naming_style.constant_case.word_separator = _
+dotnet_naming_style.constant_case.capitalization = all_upper
+
+dotnet_naming_style._privatcamalcase.required_prefix = _
+dotnet_naming_style._privatcamalcase.required_suffix =
+dotnet_naming_style._privatcamalcase.word_separator =
+dotnet_naming_style._privatcamalcase.capitalization = camel_case
+
+dotnet_naming_style.pascalcaseasync.required_prefix =
+dotnet_naming_style.pascalcaseasync.required_suffix = Async
+dotnet_naming_style.pascalcaseasync.word_separator =
+dotnet_naming_style.pascalcaseasync.capitalization = pascal_case
+
+dotnet_naming_style.typepascalcase.required_prefix = T
+dotnet_naming_style.typepascalcase.required_suffix =
+dotnet_naming_style.typepascalcase.word_separator =
+dotnet_naming_style.typepascalcase.capitalization = pascal_case
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln b/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
index 585063b..f71bc15 100644
--- a/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
@@ -5,7 +5,15 @@ VisualStudioVersion = 17.10.35122.118
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cop.Borovkov.Var3", "Cop.Borovkov.Var3\Cop.Borovkov.Var3.csproj", "{A8604186-0CDE-4504-805B-46104141269A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCustomComponents", "TestCustomComponents\TestCustomComponents.csproj", "{E2C46D08-ACCE-4547-922B-E92AD76D99C8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCustomComponents", "TestCustomComponents\TestCustomComponents.csproj", "{E2C46D08-ACCE-4547-922B-E92AD76D99C8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lab3", "Lab3\Lab3.csproj", "{1E630CC7-090F-471C-ADA1-74107CF3DC2A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lab3.Database", "Lab3.Database\Lab3.Database.csproj", "{698DE9E8-7885-4F98-AFE3-9A9C6CD2FCF5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lab4", "Lab4\Lab4.csproj", "{FAE92C0B-0A2D-48B6-A55C-DE58A310CD58}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lab4.Plugins", "Lab4.Plugins\Lab4.Plugins.csproj", "{F30C8C78-98CB-4C5E-BEE8-125791A9D7AF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,6 +29,22 @@ Global
{E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1E630CC7-090F-471C-ADA1-74107CF3DC2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E630CC7-090F-471C-ADA1-74107CF3DC2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E630CC7-090F-471C-ADA1-74107CF3DC2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E630CC7-090F-471C-ADA1-74107CF3DC2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {698DE9E8-7885-4F98-AFE3-9A9C6CD2FCF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {698DE9E8-7885-4F98-AFE3-9A9C6CD2FCF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {698DE9E8-7885-4F98-AFE3-9A9C6CD2FCF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {698DE9E8-7885-4F98-AFE3-9A9C6CD2FCF5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FAE92C0B-0A2D-48B6-A55C-DE58A310CD58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FAE92C0B-0A2D-48B6-A55C-DE58A310CD58}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FAE92C0B-0A2D-48B6-A55C-DE58A310CD58}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FAE92C0B-0A2D-48B6-A55C-DE58A310CD58}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F30C8C78-98CB-4C5E-BEE8-125791A9D7AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F30C8C78-98CB-4C5E-BEE8-125791A9D7AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F30C8C78-98CB-4C5E-BEE8-125791A9D7AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F30C8C78-98CB-4C5E-BEE8-125791A9D7AF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs
index 477bb22..0169e86 100644
--- a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs
@@ -41,7 +41,7 @@ namespace Cop.Borovkov.Var3.Components
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
}
- outDataGridView.Columns.Add(column);
+ _ = outDataGridView.Columns.Add(column);
}
}
@@ -108,10 +108,10 @@ namespace Cop.Borovkov.Var3.Components
Type type = typeof(TType);
- for (int i = 0; i < insertValues.Count(); ++i)
+ for (int i = 0; i < insertValues.Count; ++i)
{
var row = insertValues[i];
- outDataGridView.Rows.Add();
+ _ = outDataGridView.Rows.Add();
for (int j = 0; j < outDataGridView.ColumnCount; ++j)
{
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.Designer.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.Designer.cs
new file mode 100644
index 0000000..eaed0e9
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.Designer.cs
@@ -0,0 +1,36 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ partial class CustomPdfHistogram
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.cs
new file mode 100644
index 0000000..b95aba0
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfHistogram.cs
@@ -0,0 +1,68 @@
+using Cop.Borovkov.Var3.Models;
+using PIHelperSh.PdfCreator;
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Models.PieChartModel;
+using System.ComponentModel;
+using static System.Runtime.InteropServices.Marshalling.IIUnknownCacheStrategy;
+
+namespace Cop.Borovkov.Var3.Components
+{
+ public partial class CustomPdfHistogram : Component
+ {
+ public CustomPdfHistogram()
+ {
+ InitializeComponent();
+ }
+
+ public CustomPdfHistogram(IContainer container)
+ {
+ container.Add(this);
+
+ InitializeComponent();
+ }
+
+ ///
+ /// Сохранить гистограмму в пдф
+ ///
+ ///
+ public void SaveToPdf(PdfHistigramInfo histogramInfo)
+ {
+ if (string.IsNullOrEmpty(histogramInfo.FilePath))
+ throw new ArgumentException("Путь к файлу не должен быть пустым.");
+ if (string.IsNullOrEmpty(histogramInfo.DocumentTitle))
+ throw new ArgumentException("Название документа не должно быть пустым.");
+ if (string.IsNullOrEmpty(histogramInfo.HistogramTitle))
+ throw new ArgumentException("Заголовок диаграммы не должен быть пустым.");
+ if (histogramInfo.Values == null || histogramInfo.Values.Count() == 0)
+ throw new ArgumentException("Набор данных не должен быть пустым.");
+
+ foreach (var data in histogramInfo.Values)
+ {
+ if (string.IsNullOrEmpty(data.Name) || data.Points == null || data.Points.Count() == 0)
+ throw new ArgumentException($"Набор данных для серии '{data.Name}' некорректен.");
+ }
+
+ PdfCreator creator = new PdfCreator();
+
+ creator.AddParagraph(new()
+ {
+ Style = PdfStyleType.Title,
+ Text = histogramInfo.DocumentTitle,
+ MarginAfter = PdfMargin.Smal,
+ });
+
+ creator.AddHistogram(new()
+ {
+ ChartName = histogramInfo.HistogramTitle,
+ LegendPosition = histogramInfo.LegendPosition,
+ DataSet = histogramInfo.Values.Select(l => new PdfHistogramData()
+ {
+ DisplayName = l.Name,
+ Value = l.Points.Select(p => (p.Name, p.Value))
+ }).ToList()
+ });
+
+ creator.SavePdf(histogramInfo.FilePath);
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.Designer.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.Designer.cs
new file mode 100644
index 0000000..8f614a5
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.Designer.cs
@@ -0,0 +1,36 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ partial class CustomPdfTableWithGrouping
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.cs
new file mode 100644
index 0000000..e187fbc
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomPdfTableWithGrouping.cs
@@ -0,0 +1,73 @@
+using Cop.Borovkov.Var3.Models;
+using PIHelperSh.PdfCreator.Models.TableModels;
+using PIHelperSh.PdfCreator;
+using System.ComponentModel;
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace Cop.Borovkov.Var3.Components
+{
+ ///
+ /// Компонент создающий таблицу и группирует элементы по 1 столбцу
+ ///
+ public partial class CustomPdfTableWithGrouping : Component
+ {
+ ///
+ ///
+ public CustomPdfTableWithGrouping()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ ///
+ ///
+ public CustomPdfTableWithGrouping(IContainer container)
+ {
+ container.Add(this);
+ InitializeComponent();
+ }
+
+ ///
+ /// Сохранить набор таблиц в пдф
+ ///
+ ///
+ ///
+ ///
+ public void SaveToPdf(PdfTableWithGroupingInfo tableInfo) where TType : class
+ {
+ if (!tableInfo.Columns.Any() || !tableInfo.Rows.Any())
+ {
+ return;
+ }
+
+ PdfCreator creator = new PdfCreator();
+
+ creator.AddParagraph(new()
+ {
+ Style = PdfStyleType.Title,
+ Text = tableInfo.Title,
+ MarginAfter = PdfMargin.Smal,
+ });
+
+ creator.AddTable(new PdfTable()
+ {
+ Header = tableInfo.Columns.Select(c => new PdfTableColumn()
+ {
+ Title = c.Header,
+ Size = c.Width,
+ PropertyName = c.PropertyName,
+ } as IPdfColumnItem).ToList(),
+
+ Records = tableInfo.Rows
+ .OrderBy(r => typeof(TType)
+ .GetProperty(tableInfo.Columns.First().PropertyName)!.GetValue(r.Value))
+ .Select(r => (r.Value, r.Height))
+ .ToList(),
+ HeaderHeaight = tableInfo.HeaderHeight,
+ });
+
+ creator.SavePdf(tableInfo.FilePath);
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Cop.Borovkov.Var3.csproj b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Cop.Borovkov.Var3.csproj
index 3e210aa..7fd5f42 100644
--- a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Cop.Borovkov.Var3.csproj
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Cop.Borovkov.Var3.csproj
@@ -5,6 +5,28 @@
enable
true
enable
+ True
+ $(AssemblyName)
+ $(VersionPrefix)8.0.2
+
+
+ \
+ True
+
+
+
+
+
+
+
+
+
+
+ \
+ True
+
+
+
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ChartPoint.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ChartPoint.cs
new file mode 100644
index 0000000..148b689
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ChartPoint.cs
@@ -0,0 +1,18 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ ///
+ /// Точка
+ ///
+ public record ChartPoint
+ {
+ ///
+ /// Имя
+ ///
+ public required string Name { get; init; } = string.Empty;
+
+ ///
+ /// Значение
+ ///
+ public required double Value { get; init; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ColumnInfo.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ColumnInfo.cs
new file mode 100644
index 0000000..ea874e1
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/ColumnInfo.cs
@@ -0,0 +1,9 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ public record ColumnInfo
+ {
+ public string Header { get; init; } = null!;
+ public string PropertyName { get; init; } = null!;
+ public float Width { get; init; } = 3;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistigramInfo.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistigramInfo.cs
new file mode 100644
index 0000000..607fad5
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistigramInfo.cs
@@ -0,0 +1,35 @@
+using PIHelperSh.PdfCreator.Enums;
+
+namespace Cop.Borovkov.Var3.Models
+{
+ ///
+ /// Параметры для создания линейной диаграммы
+ ///
+ public record PdfHistigramInfo
+ {
+ ///
+ /// Имя файла (включая путь до файла)
+ ///
+ public string FilePath { get; init; } = @"C:\pdfTable.pdf";
+
+ ///
+ /// Заголовок документа
+ ///
+ public string DocumentTitle { get; init; } = "Гистограмма";
+
+ ///
+ /// Заголовок диаграммы
+ ///
+ public string HistogramTitle { get; init; } = "Гистограмма";
+
+ ///
+ /// Расположение легенды
+ ///
+ public PdfLegendPosition LegendPosition { get; init; } = PdfLegendPosition.Bottom;
+
+ ///
+ /// Значения
+ ///
+ public required IEnumerable Values { get; init; }
+}
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistogramLineInfo.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistogramLineInfo.cs
new file mode 100644
index 0000000..845036f
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfHistogramLineInfo.cs
@@ -0,0 +1,15 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ public record PdfHistogramLineInfo
+ {
+ ///
+ /// Название графика
+ ///
+ public required string Name { get; init; }
+
+ ///
+ /// Значения
+ ///
+ public required IEnumerable Points { get; init; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfTableWithGroupingInfo.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfTableWithGroupingInfo.cs
new file mode 100644
index 0000000..20f5b1f
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/PdfTableWithGroupingInfo.cs
@@ -0,0 +1,33 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ ///
+ /// Параметры для создания таблицы в пдф с группировкой по 1 столбцу
+ ///
+ public class PdfTableWithGroupingInfo where TType : class
+ {
+ ///
+ /// имя файла (включая путь до файла)
+ ///
+ public string FilePath { get; init; } = @"C:\pdfTable.pdf";
+
+ ///
+ /// название документа(заголовок в документе)
+ ///
+ public string Title { get; init; } = "Таблица";
+
+ ///
+ /// Высота заголовков
+ ///
+ public float HeaderHeight { get; init; } = 0.5f;
+
+ ///
+ /// Параметры столбцов
+ ///
+ public IEnumerable Columns { get; init; } = [];
+
+ ///
+ /// Список таблиц
+ ///
+ public IEnumerable> Rows { get; init; } = [];
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/RowInfo.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/RowInfo.cs
new file mode 100644
index 0000000..1693002
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/RowInfo.cs
@@ -0,0 +1,19 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ ///
+ /// Информация о строке
+ ///
+ ///
+ public record RowInfo where T : class
+ {
+ ///
+ /// Высота строки
+ ///
+ public float Height { get; set; } = 0.5f;
+
+ ///
+ /// Значение строки
+ ///
+ public T Value { get; set; } = null!;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfAlignmentType.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfAlignmentType.cs
new file mode 100644
index 0000000..62bc7f7
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfAlignmentType.cs
@@ -0,0 +1,32 @@
+using MigraDoc.DocumentObjectModel;
+using PIHelperSh.Core.Attributes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Enums
+{
+ ///
+ /// Тип выравнивания элементов
+ ///
+ public enum PdfAlignmentType
+ {
+ ///
+ /// По центру
+ ///
+ [TypeValue(ParagraphAlignment.Center)]
+ Center,
+ ///
+ /// По левому краю
+ ///
+ [TypeValue(ParagraphAlignment.Left)]
+ Left,
+ ///
+ /// По правому краю
+ ///
+ [TypeValue(ParagraphAlignment.Right)]
+ Rigth
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfLegendPosition.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfLegendPosition.cs
new file mode 100644
index 0000000..2e0c297
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfLegendPosition.cs
@@ -0,0 +1,25 @@
+namespace PIHelperSh.PdfCreator.Enums
+{
+ ///
+ /// Варианты расположения легенды
+ ///
+ public enum PdfLegendPosition
+ {
+ ///
+ /// Снизу(по умолчанию)
+ ///
+ Bottom,
+ ///
+ /// Справа
+ ///
+ Right,
+ ///
+ /// Слева
+ ///
+ Left,
+ ///
+ /// Сверху
+ ///
+ Top
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfMargin.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfMargin.cs
new file mode 100644
index 0000000..fed1c83
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfMargin.cs
@@ -0,0 +1,36 @@
+using PIHelperSh.Core.Attributes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Enums
+{
+ ///
+ /// Типы отступов после элементов (вертикальный)
+ ///
+ public enum PdfMargin
+ {
+ ///
+ /// Отступа нет
+ ///
+ [TypeValue("0cm")]
+ None,
+ ///
+ /// Отступ небольшой
+ ///
+ [TypeValue("0.3cm")]
+ Smal,
+ ///
+ /// Отступ средний
+ ///
+ [TypeValue("1cm")]
+ Medium,
+ ///
+ /// Отступ большой
+ ///
+ [TypeValue("1.6cm")]
+ Big
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfStyleType.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfStyleType.cs
new file mode 100644
index 0000000..57b4a5c
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Enums/PdfStyleType.cs
@@ -0,0 +1,54 @@
+using PIHelperSh.Core.Attributes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Enums
+{
+ ///
+ /// Типы стилей в документе
+ ///
+ public enum PdfStyleType
+ {
+ ///
+ /// Основная часть документа
+ ///
+ [TypeValue("Normal")]
+ Basic,
+ ///
+ /// Название документа
+ ///
+ [TypeValue("NormalTitle")]
+ Title,
+ ///
+ /// Уровень в списке 1
+ ///
+ [TypeValue("BulletList")]
+ [TypeValue(1)]
+ ListLevel1,
+ ///
+ /// Уровень в списке 2
+ ///
+ [TypeValue("BulletList2")]
+ [TypeValue(2)]
+ ListLevel2,
+ ///
+ /// Уровень в списке 3
+ ///
+ [TypeValue("BulletList3")]
+ [TypeValue(3)]
+ ListLevel3,
+ ///
+ /// Жирный шрифт
+ ///
+ [TypeValue("NormalBold")]
+ Bold,
+ ///
+ /// Мелкий шрифт
+ ///
+ [TypeValue("NormalSmall")]
+ Small
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfColumnItem.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfColumnItem.cs
new file mode 100644
index 0000000..ba6ba55
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfColumnItem.cs
@@ -0,0 +1,15 @@
+namespace PIHelperSh.PdfCreator.Interfaces
+{
+ ///
+ ///
+ public interface IPdfColumnItem
+ {
+ ///
+ ///
+ public float? Size { get; }
+
+ ///
+ ///
+ public string? Title { get; set; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfCreator.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfCreator.cs
new file mode 100644
index 0000000..a2d87b5
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfCreator.cs
@@ -0,0 +1,64 @@
+using PIHelperSh.PdfCreator.Models.ImageModels;
+using PIHelperSh.PdfCreator.Models.PieChartModel;
+using PIHelperSh.PdfCreator.Models.TableModels;
+using PIHelperSh.PdfCreator.Models.TextModels;
+
+namespace PIHelperSh.PdfCreator.Interfaces
+{
+ ///
+ /// Создатель pdf документа
+ ///
+ public interface IPdfCreator
+ {
+ ///
+ /// Создаём параграф
+ ///
+ /// Модель параграфа, который вставляем
+ public void AddParagraph(PdfParagraph paragraph);
+
+ ///
+ /// Создаём маркированный список
+ ///
+ /// Модель списка(может быть многоуровневым). Max - 3 уровня
+ public void AddList(PdfList List);
+
+ ///
+ /// Создаёт таблицу, с шапкой из 2-х строк(с группировками)
+ ///
+ /// Тип DTO, из которой берутся данные в таблицу
+ /// Модель самой таблицы
+ ///
+ public void AddTable(PdfTable header, bool rowHeaded = false);
+
+ ///
+ /// Создаёт табличку, наподобие той, что с T, но проще
+ ///
+ ///
+ public void AddSimpleTable(PDFSimpleTable tableData);
+
+ ///
+ /// Создаёт круговую диаграмму.
+ ///
+ /// Модель для круговой диаграммы
+ public void AddChart(PdfPieChartModel pieChart);
+
+ ///
+ /// Добавляем на лист изображение. Можно по пути, можно по потоку, можно по Base64 строке
+ ///
+ /// Модель одного изображения
+ public void AddImage(PdfImage image);
+
+ ///
+ /// Метод сохранения созданного PDF документа
+ ///
+ /// Поток MemoryStream с документом
+ public MemoryStream SavePdf();
+
+ ///
+ /// Метод сохранения созданного PDF документа в файл
+ ///
+ /// Имя файла и путь до него. Проверки на расширение нет
+ public void SavePdf(string filename);
+
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfElement.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfElement.cs
new file mode 100644
index 0000000..3d6fb42
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Interfaces/IPdfElement.cs
@@ -0,0 +1,20 @@
+using PIHelperSh.PdfCreator.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Interfaces
+{
+ ///
+ /// Аналогично word этот интерфейс нужен для работы списков.
+ ///
+ public interface IPdfElement
+ {
+ ///
+ /// //Отступ после(может быть и у списков и у параграфов)
+ ///
+ PdfMargin MarginAfter { get; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/MiraDocImage.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/MiraDocImage.cs
new file mode 100644
index 0000000..6aaa5ac
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/MiraDocImage.cs
@@ -0,0 +1,75 @@
+namespace PIHelperSh.PdfCreator.Models.ImageModels
+{
+ ///
+ /// Удобный метод для хранения изображений (для создания Pdf документа можно использовать либо путь до фото, либо поток с данными о нём)
+ ///
+ public class MiraDocImage
+ {
+ ///
+ /// Путь до фото
+ ///
+ public string? Path { get; set; } = null;
+
+ ///
+ /// Поток фото
+ ///
+ public Stream? Source
+ {
+ get => _source;
+ set
+ {
+ _source = value;
+ _b64Source = null;
+ }
+ }
+
+ private Stream? _source;
+
+ private string? _b64Source = null;
+
+ ///
+ /// Создание изображения из пути
+ ///
+ /// Путь
+ ///
+ public static MiraDocImage CreateFromPath(string path) => new() { Path = path };
+
+ ///
+ /// Создания изображения из строки base64
+ ///
+ /// изображение в формате base64
+ ///
+ public static MiraDocImage CreateFromBase64(string base64) => new() { _b64Source = $"base64:{base64}" };
+
+ ///
+ /// Создание изображения из потока
+ ///
+ /// Поток
+ ///
+ public static MiraDocImage CreateFromStream(Stream stream) => new() { Source = stream };
+
+ ///
+ ///
+ ///
+ ///
+ public string GetImageForMiraDoc()
+ {
+ if (!string.IsNullOrEmpty(Path)) return Path;
+ if (_b64Source != null) return _b64Source;
+ if (_source == null) throw new ArgumentNullException("Для изображения не задан ни путь, ни поток. Необходимо заполнить как минимум одно из этого, для работы");
+ _b64Source = GetImageAsStringBase64(_source);
+ return _b64Source;
+ }
+
+ private string GetImageAsStringBase64(Stream stream)
+ {
+ //Вот это вот, в общем-то, ещё один жуткий костыль. Дело в том, что MigraDoc не поддерживает создание изображений из потоков. Только из путей. Но всё же, способ есть
+ //Вот он собственно. И да, фактически это жуткая система, записывающая картинку в строку. Увы, по другому не получится
+ stream.Position = 0;
+ int count = (int)stream.Length;
+ byte[] data = new byte[count];
+ stream.Read(data, 0, count);
+ return $"base64:{Convert.ToBase64String(data)}";
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/PdfImage.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/PdfImage.cs
new file mode 100644
index 0000000..6b52099
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/ImageModels/PdfImage.cs
@@ -0,0 +1,41 @@
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Models.ImageModels
+{
+ ///
+ /// Информация о изображении
+ ///
+ public class PdfImage : IPdfElement
+ {
+ ///
+ /// Путь до изображения
+ ///
+ public MiraDocImage Image { get; set; } = null!;
+
+ ///
+ /// Ширина изображения
+ ///
+ public int? Width { get; set; } = null;
+
+ ///
+ /// Высота изображения
+ ///
+ public int? Height { get; set; } = null;
+
+ ///
+ /// Выравнивание текста внутри параграфа (по умолчанию - по левой стороне)
+ ///
+ public PdfAlignmentType ImageAlignment { get; set; } = PdfAlignmentType.Left;
+
+ ///
+ /// Отступ после параграфа (по умолчанию средний)
+ ///
+ public PdfMargin MarginAfter { get; set; } = PdfMargin.Medium;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramData.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramData.cs
new file mode 100644
index 0000000..6bb07bb
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramData.cs
@@ -0,0 +1,42 @@
+using System.Drawing;
+
+namespace PIHelperSh.PdfCreator.Models.PieChartModel
+{
+ ///
+ /// Элемент данных. Одно значение для диаграммы.
+ ///
+ public class PdfHistogramData
+ {
+ ///
+ /// Название варианта
+ ///
+ public string DisplayName { get; set; } = null!;
+
+ ///
+ /// Значение варианта(по ним строят диаграмму)
+ ///
+ public IEnumerable<(string Name, double Value)> Value { get; set; }
+
+ ///
+ /// Цвет области на диаграмме. При null будет использоваться выдача цветов по умолчанию)
+ ///
+ public Color? Color { get; set; } = null;
+
+ ///
+ ///
+ public PdfHistogramData()
+ {
+ Value = [];
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public PdfHistogramData(string displayName, IEnumerable<(string, double)> value)
+ {
+ DisplayName = displayName;
+ Value = value;
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramModel.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramModel.cs
new file mode 100644
index 0000000..c4fe900
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfHistogramModel.cs
@@ -0,0 +1,13 @@
+namespace PIHelperSh.PdfCreator.Models.PieChartModel
+{
+ ///
+ /// Модель линейной диаграммы
+ ///
+ public class PdfHistogramModel : PdfPieChartModel
+ {
+ ///
+ /// Набор данных для создания диаграммы
+ ///
+ public new List DataSet { get; set; } = [];
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartData.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartData.cs
new file mode 100644
index 0000000..2ac3137
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartData.cs
@@ -0,0 +1,39 @@
+using System.Drawing;
+
+namespace PIHelperSh.PdfCreator.Models.PieChartModel
+{
+ ///
+ /// Элемент данных. Одно значение для диаграммы.
+ ///
+ public class PdfPieChartData
+ {
+ ///
+ /// Название варианта
+ ///
+ public string DisplayName { get; set; } = null!;
+
+ ///
+ /// Значение варианта(по ним строят диаграмму)
+ ///
+ public double Value { get; set; }
+
+ ///
+ /// Цвет области на диаграмме. При null будет использоваться выдача цветов по умолчанию)
+ ///
+ public Color? Color { get; set; } = null;
+
+ ///
+ ///
+ public PdfPieChartData() { }
+
+ ///
+ ///
+ ///
+ ///
+ public PdfPieChartData(string displayName, double value)
+ {
+ DisplayName = displayName;
+ Value = value;
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartModel.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartModel.cs
new file mode 100644
index 0000000..93fd212
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/PieChartModel/PdfPieChartModel.cs
@@ -0,0 +1,45 @@
+using PIHelperSh.PdfCreator.Enums;
+
+namespace PIHelperSh.PdfCreator.Models.PieChartModel
+{
+ ///
+ /// Модель круговой диаграммы
+ ///
+ public class PdfPieChartModel
+ {
+ ///
+ /// Ширина диаграммы в см по умолчанию на всю ширину
+ ///
+ public double Width { get; set; } = 16;
+
+ ///
+ /// Высота диаграммы в см
+ ///
+ public double Height { get; set; } = 12;
+
+ ///
+ /// Заголовок диаграммы. Будет отображён над ней
+ ///
+ public string ChartName { get; set; } = null!;
+
+ ///
+ /// Стиль заголовка
+ ///
+ public PdfStyleType HeaderStyle { get; set; } = PdfStyleType.Bold;
+
+ ///
+ /// Выравнивание заголовка по горизонтали
+ ///
+ public PdfAlignmentType HeaderAlignment { get; set; } = PdfAlignmentType.Center;
+
+ ///
+ /// Вариант расположения легенды
+ ///
+ public PdfLegendPosition LegendPosition { get; set; } = PdfLegendPosition.Bottom;
+
+ ///
+ /// Набор данных для создания диаграммы
+ ///
+ public List DataSet { get; set; } = new();
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTable.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTable.cs
new file mode 100644
index 0000000..c87f560
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTable.cs
@@ -0,0 +1,51 @@
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace PIHelperSh.PdfCreator.Models.TableModels
+{
+ ///
+ /// Простая табличка в PDF
+ ///
+ public class PDFSimpleTable
+ {
+ ///
+ /// Заголовок
+ ///
+ public List? Header { get; set; } = null;
+
+ ///
+ /// Стиль заголовка (по умолчанию - жирный)
+ ///
+ public PdfStyleType HeaderStyle { get; set; } = PdfStyleType.Bold;
+
+ ///
+ /// Выравнивание текста внутри заголовка (по умолчанию - по центру)
+ ///
+ public PdfAlignmentType HeaderHorizontalAlignment { get; set; } = PdfAlignmentType.Center;
+
+ ///
+ /// Набор строк
+ ///
+ public List Rows { get; set; } = new();
+
+ ///
+ /// Базовый стиль строк
+ ///
+ public PdfStyleType RowStyle = PdfStyleType.Basic;
+
+ ///
+ /// Базовое выравнивание элементов в строке
+ ///
+ public PdfAlignmentType RowHorizontalAlignment = PdfAlignmentType.Rigth;
+
+ ///
+ /// Отступ после таблицы
+ ///
+ public PdfMargin MarginAfter = PdfMargin.None;
+
+ ///
+ /// Меняем ли ориентацию страницы на альбомную
+ ///
+ public bool ChangePageOrientation = false;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTableRow.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTableRow.cs
new file mode 100644
index 0000000..cda561a
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PDFSimpleTableRow.cs
@@ -0,0 +1,30 @@
+using PIHelperSh.PdfCreator.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Models.TableModels
+{
+ ///
+ /// Строка простой таблицы
+ ///
+ public class PDFSimpleTableRow
+ {
+ ///
+ /// Элементы данной стоки
+ ///
+ public List Items = new List();
+
+ ///
+ /// Стиль элементов строки, если он отличается от стиля строк, определённого в таблице
+ ///
+ public PdfStyleType? Style = null;
+
+ ///
+ /// Выравнивание элементов строки, если оно отличается от выравнивания, определённого в таблице
+ ///
+ public PdfAlignmentType? Alignment = null;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTable.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTable.cs
new file mode 100644
index 0000000..5812616
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTable.cs
@@ -0,0 +1,47 @@
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace PIHelperSh.PdfCreator.Models.TableModels
+{
+ ///
+ /// Таблица для вставки на лист
+ ///
+ ///
+ public class PdfTable
+ {
+ ///
+ /// Шапка таблицы(2 строки/2 столбца)
+ ///
+ public List? Header { get; set; } = null;
+
+ ///
+ /// Стиль заголовка (по умолчанию - жирный)
+ ///
+ public PdfStyleType HeaderStyle { get; set; } = PdfStyleType.Bold;
+
+ ///
+ /// Выравнивание текста внутри заголовка (по умолчанию - по центру)
+ ///
+ public PdfAlignmentType HeaderHorizontalAlignment { get; set; } = PdfAlignmentType.Center;
+
+ ///
+ /// Список объектов, информация о которых будет в таблице.
+ ///
+ public List<(T value, float height)> Records { get; set; } = new();
+
+ ///
+ /// Стиль объектов в таблице (по умолчанию - базовый)
+ ///
+ public PdfStyleType RecordStyle { get; set; } = PdfStyleType.Basic;
+
+ ///
+ /// Выравнивание текста объектов в таблице (по умолчанию - по левой стороне)
+ ///
+ public PdfAlignmentType RecordHorizontalAlignment { get; set; } = PdfAlignmentType.Left;
+
+ ///
+ /// Высота заголовка
+ ///
+ public float HeaderHeaight { get; set; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumn.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumn.cs
new file mode 100644
index 0000000..f436fdd
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumn.cs
@@ -0,0 +1,25 @@
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace PIHelperSh.PdfCreator.Models.TableModels
+{
+ ///
+ /// Столбец(строка) таблицы, определяющий дальнейшее содержимое
+ ///
+ public class PdfTableColumn : IPdfColumnItem
+ {
+ ///
+ /// Заголовок
+ ///
+ public string? Title { get; set; }
+
+ ///
+ /// Размер (Ширина столбца/Высота строки)
+ ///
+ public float? Size { get; set; }
+
+ ///
+ /// Название свойства, которое будет заполнять столбец
+ ///
+ public string PropertyName { get; set; } = null!;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumnGroup.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumnGroup.cs
new file mode 100644
index 0000000..51db426
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TableModels/PdfTableColumnGroup.cs
@@ -0,0 +1,25 @@
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace PIHelperSh.PdfCreator.Models.TableModels
+{
+ ///
+ /// Группа столбцов(строк) таблицы, определяющий дальнейшее содержимое
+ ///
+ public class PdfTableColumnGroup : IPdfColumnItem
+ {
+ ///
+ /// Заголовок
+ ///
+ public string? Title { get; set; }
+
+ ///
+ /// Количество элементов в группе
+ ///
+ public float? Size => InnerColumns.Sum(x => x.Size);
+
+ ///
+ /// Столбцы/строки в группе
+ ///
+ public List InnerColumns { get; set; } = new();
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfList.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfList.cs
new file mode 100644
index 0000000..4ae06ae
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfList.cs
@@ -0,0 +1,21 @@
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+
+namespace PIHelperSh.PdfCreator.Models.TextModels
+{
+ ///
+ /// Список элементов в PDF
+ ///
+ public class PdfList : IPdfElement
+ {
+ ///
+ /// Элементы списка (параграфы или иные списки)
+ ///
+ public List Content { get; set; } = new();
+
+ ///
+ /// Отступ после списка (по умолчанию - средний)
+ ///
+ public PdfMargin MarginAfter { get; set; } = PdfMargin.Medium;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfParagraph.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfParagraph.cs
new file mode 100644
index 0000000..d3df994
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/Models/TextModels/PdfParagraph.cs
@@ -0,0 +1,36 @@
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Interfaces;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PIHelperSh.PdfCreator.Models.TextModels
+{
+ ///
+ /// Параграф в PDF
+ ///
+ public class PdfParagraph : IPdfElement
+ {
+ ///
+ /// Текст параграфа
+ ///
+ public string Text { get; set; } = string.Empty;
+
+ ///
+ /// Стиль параграфа (по умолчанию - базовый)
+ ///
+ public PdfStyleType Style { get; set; } = PdfStyleType.Basic;
+
+ ///
+ /// Выравнивание текста внутри параграфа (по умолчанию - по левой стороне)
+ ///
+ public PdfAlignmentType ParagraphAlignment { get; set; } = PdfAlignmentType.Left;
+
+ ///
+ /// Отступ после параграфа (по умолчанию средний)
+ ///
+ public PdfMargin MarginAfter { get; set; } = PdfMargin.Medium;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/PdfCreator.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/PdfCreator.cs
new file mode 100644
index 0000000..3fecdf0
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/PdfCreator/PdfCreator.cs
@@ -0,0 +1,605 @@
+using MigraDoc.DocumentObjectModel;
+using MigraDoc.Rendering;
+using MigraDoc.DocumentObjectModel.Tables;
+using MigraDoc.DocumentObjectModel.Shapes.Charts;
+using PIHelperSh.Core.Extensions;
+using PIHelperSh.PdfCreator.Enums;
+using PIHelperSh.PdfCreator.Models.TableModels;
+using PIHelperSh.PdfCreator.Models.TextModels;
+using PIHelperSh.PdfCreator.Models.ImageModels;
+using PIHelperSh.PdfCreator.Models.PieChartModel;
+using PIHelperSh.PdfCreator.Interfaces;
+using System.Text;
+using TabAlignment = MigraDoc.DocumentObjectModel.TabAlignment;
+using System.Reflection;
+using HorizontalAlignment = MigraDoc.DocumentObjectModel.Shapes.Charts.HorizontalAlignment;
+using Color = MigraDoc.DocumentObjectModel.Color;
+
+namespace PIHelperSh.PdfCreator
+{
+ ///
+ ///
+ public class PdfCreator : IPdfCreator
+ {
+ private Document? _document;
+ private Section? _section;
+
+ private readonly Unit _borderWidth = 0.5;
+
+ ///
+ ///
+ public PdfCreator()
+ {
+ _document = new Document();
+ DefineStyles(_document);
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+ _section = _document.AddSection();
+ }
+
+ #region Внутренние методы
+ private static string GetListLavel(int level)
+ {
+ try
+ {
+ return level.CreateEnumFromValue().GetValue();
+ }
+ catch (Exception)
+ {
+ return PdfStyleType.Basic.GetValue();
+ }
+ }
+
+ private void ConfigurateChartLegend(Chart chart, PdfLegendPosition position)
+ {
+ switch (position)
+ {
+ case PdfLegendPosition.Bottom:
+ chart.FooterArea.AddLegend();
+ break;
+ case PdfLegendPosition.Right:
+ chart.RightArea.AddLegend();
+ break;
+ case PdfLegendPosition.Left:
+ chart.LeftArea.AddLegend();
+ break;
+ case PdfLegendPosition.Top:
+ chart.TopArea.AddLegend();
+ break;
+ }
+ }
+
+ private static void DefineStyles(Document document)
+ {
+ #region Базовый стиль
+ var style = document.Styles["Normal"];
+ style.Font.Name = "Times New Roman";
+ style.Font.Size = 14;
+ #endregion
+
+ #region Стиль заголовка
+ style = document.Styles.AddStyle("NormalTitle", "Normal");
+ style.Font.Bold = true;
+ style.Font.Size = 18;
+ #endregion
+
+ #region Стиль жирный
+ style = document.Styles.AddStyle("NormalBold", "Normal");
+ style.Font.Bold = true;
+ #endregion
+
+ #region Маркированный список уровень 1
+ style = document.AddStyle("BulletList", "Normal");
+ style.ParagraphFormat.LeftIndent = "1.5cm";
+ style.ParagraphFormat.ListInfo = new ListInfo
+ {
+ ContinuePreviousList = true,//Продолжать список, который уже был ранее
+ ListType = ListType.BulletList1//Маркер
+ };
+ style.ParagraphFormat.TabStops.ClearAll();
+ style.ParagraphFormat.TabStops.AddTabStop(Unit.FromCentimeter(1.5), TabAlignment.Left);
+
+ style.ParagraphFormat.FirstLineIndent = "-0.5cm";
+ #endregion
+
+ #region Маркированный список уровень 2
+ style = document.AddStyle("BulletList2", "BulletList");
+ style.ParagraphFormat.LeftIndent = "3.0cm";
+ style.ParagraphFormat.ListInfo.ListType = ListType.BulletList2;
+ style.ParagraphFormat.TabStops.ClearAll();
+ style.ParagraphFormat.TabStops.AddTabStop(Unit.FromCentimeter(3.0), TabAlignment.Left);
+ #endregion
+
+ #region Маркированный список уровень 3
+ style = document.AddStyle("BulletList3", "BulletList");
+ style.ParagraphFormat.LeftIndent = "4.5cm";
+ style.ParagraphFormat.ListInfo.ListType = ListType.BulletList3;
+ style.ParagraphFormat.TabStops.ClearAll();
+ style.ParagraphFormat.TabStops.AddTabStop(Unit.FromCentimeter(4.5), TabAlignment.Left);
+ #endregion
+
+ #region Мелкий шрифт
+ style = document.Styles.AddStyle("NormalSmall", "Normal");
+ style.Font.Size = 11;
+ #endregion
+ }
+
+ private Paragraph? MakeParagraph(PdfParagraph pdfParagraph)
+ {
+ if (_section == null)
+ return null;
+ var paragraph = _section.AddParagraph(pdfParagraph.Text);
+ paragraph.Format.Alignment = pdfParagraph.ParagraphAlignment.GetValue();
+ //Т.к стили могут назначаться по иному, тут будет вот так вот
+ return paragraph;
+ }
+
+ private Paragraph? MakeList(PdfList pdfList, int level)
+ {
+ Paragraph? last = null;
+ foreach (IPdfElement element in pdfList.Content)
+ {
+ if (element is PdfParagraph par)
+ {
+ var paragraph = MakeParagraph(par);
+ if (paragraph == null)
+ continue;
+
+ paragraph.Format.SpaceAfter = "0.3cm";
+ paragraph.Style = GetListLavel(level);
+ last = paragraph;
+ }
+ else if (element is PdfList ls)
+ {
+ last = MakeList(ls, level + 1);
+ }
+ }
+ return last;
+ }
+
+ private void ConfigurateParagraph(Paragraph paragraph, PdfParagraph properties)
+ {
+ paragraph.Format.Alignment = properties.ParagraphAlignment.GetValue(); ;
+ if (properties.MarginAfter != PdfMargin.None) paragraph.Format.SpaceAfter = properties.MarginAfter.GetValue();
+ paragraph.Style = properties.Style.GetValue();
+ }
+
+ private void ConfigurateCell(Cell cell, string text, PdfAlignmentType alignment, PdfStyleType style, int? rightMerge = null, int? downMerge = null, bool dcw = false)
+ {
+ if (rightMerge.HasValue) cell.MergeRight = rightMerge.Value;
+ if (downMerge.HasValue)
+ {
+ cell.MergeDown = downMerge.Value;
+ cell.VerticalAlignment = VerticalAlignment.Center;
+ }
+
+ Paragraph paragraph = cell.AddParagraph(text);
+ ConfigurateParagraph(paragraph, new()
+ {
+ ParagraphAlignment = alignment,
+ Style = style,
+ MarginAfter = PdfMargin.None
+ });
+
+ cell.Borders.Left.Width = _borderWidth;
+ cell.Borders.Right.Width = _borderWidth;
+ cell.Borders.Top.Width = _borderWidth;
+ cell.Borders.Bottom.Width = _borderWidth;
+
+ if (dcw)
+ {
+ float columnNeeds = text.Length / 3.8f;
+ if (cell.Column.Width.Centimeter < columnNeeds)
+ cell.Column.Width = Unit.FromCentimeter(columnNeeds);
+ }
+ }
+
+ private Func