diff --git a/Lab 2/Belianin_2/Belianin_2.sln b/Lab 2/Belianin_2/Belianin_2.sln new file mode 100644 index 0000000..b133bd4 --- /dev/null +++ b/Lab 2/Belianin_2/Belianin_2.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyCustomComponents", "MyCustomComponents\MyCustomComponents.csproj", "{33B0240F-25C6-4577-BE81-5381D939E230}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesktopWithMyVisualComponents", "DesktopWithMyVisualComponents\DesktopWithMyVisualComponents.csproj", "{D784BAED-C48F-46F2-A6A0-BBD6CE599A59}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33B0240F-25C6-4577-BE81-5381D939E230}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33B0240F-25C6-4577-BE81-5381D939E230}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33B0240F-25C6-4577-BE81-5381D939E230}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33B0240F-25C6-4577-BE81-5381D939E230}.Release|Any CPU.Build.0 = Release|Any CPU + {D784BAED-C48F-46F2-A6A0-BBD6CE599A59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D784BAED-C48F-46F2-A6A0-BBD6CE599A59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D784BAED-C48F-46F2-A6A0-BBD6CE599A59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D784BAED-C48F-46F2-A6A0-BBD6CE599A59}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {26502496-F9AE-4E02-986A-76FD9595E9AE} + EndGlobalSection +EndGlobal diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj new file mode 100644 index 0000000..c27ce9b --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj @@ -0,0 +1,21 @@ + + + + WinExe + net6.0-windows + enable + true + enable + + + + + + + + + + + + + \ No newline at end of file diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Device.cs b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Device.cs new file mode 100644 index 0000000..5cc393b --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Device.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DesktopWithMyVisualComponents +{ + public class Device + { + public int Id { get; set; } + + public string DeviceType { get; set; } + + public string Model { get; set; } + + public string SerialNumber { get; set; } + + public string Owner { get; set; } + + public DateTime PurchaseDate { get; set; } + + public string State { get; set; } + + public string Color { get; set; } + + public int WarrantyPeriod { get; set; } + + public int Price { get; set; } + + public Device(string serialNumber, string deviceType, string model) + { + SerialNumber = serialNumber; + Model = model; + DeviceType = deviceType; + } + + public Device() { } + } +} diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.Designer.cs b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.Designer.cs new file mode 100644 index 0000000..6de219f --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.Designer.cs @@ -0,0 +1,424 @@ +namespace DesktopWithMyVisualComponents +{ + partial class FormMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.customInputRangeNumber = new MyCustomComponents.CustomInputRangeNumber(); + this.buttonCheck = new System.Windows.Forms.Button(); + this.labelCheckValue = new System.Windows.Forms.Label(); + this.groupBoxInput = new System.Windows.Forms.GroupBox(); + this.groupBoxSelected = new System.Windows.Forms.GroupBox(); + this.buttonGetSelected = new System.Windows.Forms.Button(); + this.labelSelectedValue = new System.Windows.Forms.Label(); + this.buttonClear = new System.Windows.Forms.Button(); + this.buttonAdd = new System.Windows.Forms.Button(); + this.textBoxAdd = new System.Windows.Forms.TextBox(); + this.customSelectedCheckedListBoxProperty = new MyCustomComponents.CustomSelectedCheckedListBoxProperty(); + this.groupBoxData = new System.Windows.Forms.GroupBox(); + this.labelDeviceType = new System.Windows.Forms.Label(); + this.labelModel = new System.Windows.Forms.Label(); + this.labelRegNum = new System.Windows.Forms.Label(); + this.buttonGetFromTree = new System.Windows.Forms.Button(); + this.buttonAddToTree = new System.Windows.Forms.Button(); + this.comboBoxDeviceType = new System.Windows.Forms.ComboBox(); + this.textBoxModel = new System.Windows.Forms.TextBox(); + this.textBoxSerialNumber = new System.Windows.Forms.TextBox(); + this.customTreeView = new MyCustomComponents.CustomTreeView(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.Visual = new System.Windows.Forms.TabPage(); + this.Docs = new System.Windows.Forms.TabPage(); + this.buttonWordWithDiagram = new System.Windows.Forms.Button(); + this.buttonWordWithTable = new System.Windows.Forms.Button(); + this.buttonWordWithImage = new System.Windows.Forms.Button(); + this.wordWithImages = new MyCustomComponents.WordWithImages(this.components); + this.wordWithTable = new MyCustomComponents.WordWithTable(this.components); + this.wordWithDiagram = new MyCustomComponents.WordWithDiagram(this.components); + this.groupBoxInput.SuspendLayout(); + this.groupBoxSelected.SuspendLayout(); + this.groupBoxData.SuspendLayout(); + this.tabControl.SuspendLayout(); + this.Visual.SuspendLayout(); + this.Docs.SuspendLayout(); + this.SuspendLayout(); + // + // customInputRangeNumber + // + this.customInputRangeNumber.AutoValidate = System.Windows.Forms.AutoValidate.Disable; + this.customInputRangeNumber.CausesValidation = false; + this.customInputRangeNumber.Location = new System.Drawing.Point(34, 25); + this.customInputRangeNumber.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); + this.customInputRangeNumber.MaxValue = new decimal(new int[] { -1, -1, -1, 0}); + this.customInputRangeNumber.MinValue = new decimal(new int[] { -1, -1, -1, -2147483648}); + this.customInputRangeNumber.Name = "customInputRangeNumber"; + this.customInputRangeNumber.Size = new System.Drawing.Size(144, 40); + this.customInputRangeNumber.TabIndex = 0; + this.customInputRangeNumber.Value = new decimal(new int[] { 0, 0, 0, 0}); + // + // buttonCheck + // + this.buttonCheck.Location = new System.Drawing.Point(193, 29); + this.buttonCheck.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonCheck.Name = "buttonCheck"; + this.buttonCheck.Size = new System.Drawing.Size(144, 31); + this.buttonCheck.TabIndex = 1; + this.buttonCheck.Text = "Check"; + this.buttonCheck.UseVisualStyleBackColor = true; + this.buttonCheck.Click += new System.EventHandler(this.buttonCheck_Click); + // + // labelCheckValue + // + this.labelCheckValue.AutoSize = true; + this.labelCheckValue.Location = new System.Drawing.Point(34, 148); + this.labelCheckValue.Name = "labelCheckValue"; + this.labelCheckValue.Size = new System.Drawing.Size(82, 20); + this.labelCheckValue.TabIndex = 2; + this.labelCheckValue.Text = "Enter value"; + // + // groupBoxInput + // + this.groupBoxInput.Controls.Add(this.customInputRangeNumber); + this.groupBoxInput.Controls.Add(this.labelCheckValue); + this.groupBoxInput.Controls.Add(this.buttonCheck); + this.groupBoxInput.Location = new System.Drawing.Point(7, 8); + this.groupBoxInput.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxInput.Name = "groupBoxInput"; + this.groupBoxInput.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxInput.Size = new System.Drawing.Size(355, 253); + this.groupBoxInput.TabIndex = 9; + this.groupBoxInput.TabStop = false; + this.groupBoxInput.Text = "Input"; + // + // groupBoxSelected + // + this.groupBoxSelected.Controls.Add(this.buttonGetSelected); + this.groupBoxSelected.Controls.Add(this.labelSelectedValue); + this.groupBoxSelected.Controls.Add(this.buttonClear); + this.groupBoxSelected.Controls.Add(this.buttonAdd); + this.groupBoxSelected.Controls.Add(this.textBoxAdd); + this.groupBoxSelected.Controls.Add(this.customSelectedCheckedListBoxProperty); + this.groupBoxSelected.Location = new System.Drawing.Point(370, 8); + this.groupBoxSelected.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxSelected.Name = "groupBoxSelected"; + this.groupBoxSelected.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxSelected.Size = new System.Drawing.Size(355, 253); + this.groupBoxSelected.TabIndex = 10; + this.groupBoxSelected.TabStop = false; + this.groupBoxSelected.Text = "Selected"; + // + // buttonGetSelected + // + this.buttonGetSelected.Location = new System.Drawing.Point(219, 192); + this.buttonGetSelected.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonGetSelected.Name = "buttonGetSelected"; + this.buttonGetSelected.Size = new System.Drawing.Size(114, 31); + this.buttonGetSelected.TabIndex = 14; + this.buttonGetSelected.Text = "Get Selected"; + this.buttonGetSelected.UseVisualStyleBackColor = true; + this.buttonGetSelected.Click += new System.EventHandler(this.buttonGetSelected_Click); + // + // labelSelectedValue + // + this.labelSelectedValue.AutoSize = true; + this.labelSelectedValue.Location = new System.Drawing.Point(219, 148); + this.labelSelectedValue.Name = "labelSelectedValue"; + this.labelSelectedValue.Size = new System.Drawing.Size(105, 20); + this.labelSelectedValue.TabIndex = 11; + this.labelSelectedValue.Text = "Selected value"; + // + // buttonClear + // + this.buttonClear.Location = new System.Drawing.Point(219, 108); + this.buttonClear.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonClear.Name = "buttonClear"; + this.buttonClear.Size = new System.Drawing.Size(114, 31); + this.buttonClear.TabIndex = 13; + this.buttonClear.Text = "Clear"; + this.buttonClear.UseVisualStyleBackColor = true; + this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click); + // + // buttonAdd + // + this.buttonAdd.Location = new System.Drawing.Point(219, 69); + this.buttonAdd.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonAdd.Name = "buttonAdd"; + this.buttonAdd.Size = new System.Drawing.Size(114, 31); + this.buttonAdd.TabIndex = 12; + this.buttonAdd.Text = "Add or Select"; + this.buttonAdd.UseVisualStyleBackColor = true; + this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click); + // + // textBoxAdd + // + this.textBoxAdd.Location = new System.Drawing.Point(219, 31); + this.textBoxAdd.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.textBoxAdd.Name = "textBoxAdd"; + this.textBoxAdd.Size = new System.Drawing.Size(114, 27); + this.textBoxAdd.TabIndex = 11; + // + // customSelectedCheckedListBoxProperty + // + this.customSelectedCheckedListBoxProperty.Location = new System.Drawing.Point(41, 25); + this.customSelectedCheckedListBoxProperty.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); + this.customSelectedCheckedListBoxProperty.Name = "customSelectedCheckedListBoxProperty"; + this.customSelectedCheckedListBoxProperty.SelectedElement = ""; + this.customSelectedCheckedListBoxProperty.Size = new System.Drawing.Size(171, 209); + this.customSelectedCheckedListBoxProperty.TabIndex = 0; + // + // groupBoxData + // + this.groupBoxData.Controls.Add(this.labelDeviceType); + this.groupBoxData.Controls.Add(this.labelModel); + this.groupBoxData.Controls.Add(this.labelRegNum); + this.groupBoxData.Controls.Add(this.buttonGetFromTree); + this.groupBoxData.Controls.Add(this.buttonAddToTree); + this.groupBoxData.Controls.Add(this.comboBoxDeviceType); + this.groupBoxData.Controls.Add(this.textBoxModel); + this.groupBoxData.Controls.Add(this.textBoxSerialNumber); + this.groupBoxData.Controls.Add(this.customTreeView); + this.groupBoxData.Location = new System.Drawing.Point(7, 269); + this.groupBoxData.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxData.Name = "groupBoxData"; + this.groupBoxData.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.groupBoxData.Size = new System.Drawing.Size(719, 307); + this.groupBoxData.TabIndex = 11; + this.groupBoxData.TabStop = false; + this.groupBoxData.Text = "Data"; + // + // labelDeviceType + // + this.labelDeviceType.AutoSize = true; + this.labelDeviceType.Location = new System.Drawing.Point(494, 155); + this.labelDeviceType.Name = "labelDeviceType"; + this.labelDeviceType.Size = new System.Drawing.Size(119, 20); + this.labelDeviceType.TabIndex = 8; + this.labelDeviceType.Text = "Тип устройства"; + // + // labelModel + // + this.labelModel.AutoSize = true; + this.labelModel.Location = new System.Drawing.Point(494, 96); + this.labelModel.Name = "labelModel"; + this.labelModel.Size = new System.Drawing.Size(63, 20); + this.labelModel.TabIndex = 7; + this.labelModel.Text = "Модель"; + // + // labelRegNum + // + this.labelRegNum.AutoSize = true; + this.labelRegNum.Location = new System.Drawing.Point(494, 37); + this.labelRegNum.Name = "labelRegNum"; + this.labelRegNum.Size = new System.Drawing.Size(185, 20); + this.labelRegNum.TabIndex = 6; + this.labelRegNum.Text = "Регистрационный номер"; + // + // buttonGetFromTree + // + this.buttonGetFromTree.Location = new System.Drawing.Point(494, 260); + this.buttonGetFromTree.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonGetFromTree.Name = "buttonGetFromTree"; + this.buttonGetFromTree.Size = new System.Drawing.Size(215, 31); + this.buttonGetFromTree.TabIndex = 5; + this.buttonGetFromTree.Text = "Get Selected"; + this.buttonGetFromTree.UseVisualStyleBackColor = true; + this.buttonGetFromTree.Click += new System.EventHandler(this.buttonGetFromTree_Click); + // + // buttonAddToTree + // + this.buttonAddToTree.Location = new System.Drawing.Point(494, 221); + this.buttonAddToTree.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonAddToTree.Name = "buttonAddToTree"; + this.buttonAddToTree.Size = new System.Drawing.Size(215, 31); + this.buttonAddToTree.TabIndex = 4; + this.buttonAddToTree.Text = "Add"; + this.buttonAddToTree.UseVisualStyleBackColor = true; + this.buttonAddToTree.Click += new System.EventHandler(this.buttonAddToTree_Click); + // + // comboBoxDeviceType + // + this.comboBoxDeviceType.FormattingEnabled = true; + this.comboBoxDeviceType.Location = new System.Drawing.Point(494, 179); + this.comboBoxDeviceType.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.comboBoxDeviceType.Name = "comboBoxDeviceType"; + this.comboBoxDeviceType.Size = new System.Drawing.Size(214, 28); + this.comboBoxDeviceType.TabIndex = 3; + // + // textBoxModel + // + this.textBoxModel.Location = new System.Drawing.Point(494, 120); + this.textBoxModel.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.textBoxModel.Name = "textBoxModel"; + this.textBoxModel.Size = new System.Drawing.Size(214, 27); + this.textBoxModel.TabIndex = 2; + // + // textBoxSerialNumber + // + this.textBoxSerialNumber.Location = new System.Drawing.Point(494, 61); + this.textBoxSerialNumber.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.textBoxSerialNumber.Name = "textBoxSerialNumber"; + this.textBoxSerialNumber.Size = new System.Drawing.Size(214, 27); + this.textBoxSerialNumber.TabIndex = 1; + // + // customTreeView + // + this.customTreeView.Location = new System.Drawing.Point(17, 29); + this.customTreeView.Margin = new System.Windows.Forms.Padding(3, 5, 3, 5); + this.customTreeView.Name = "customTreeView"; + this.customTreeView.Size = new System.Drawing.Size(455, 269); + this.customTreeView.TabIndex = 0; + // + // tabControl + // + this.tabControl.Controls.Add(this.Visual); + this.tabControl.Controls.Add(this.Docs); + this.tabControl.Location = new System.Drawing.Point(14, 16); + this.tabControl.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(746, 621); + this.tabControl.TabIndex = 12; + // + // Visual + // + this.Visual.Controls.Add(this.groupBoxData); + this.Visual.Controls.Add(this.groupBoxInput); + this.Visual.Controls.Add(this.groupBoxSelected); + this.Visual.Location = new System.Drawing.Point(4, 29); + this.Visual.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Visual.Name = "Visual"; + this.Visual.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Visual.Size = new System.Drawing.Size(738, 588); + this.Visual.TabIndex = 0; + this.Visual.Text = "Visual"; + this.Visual.UseVisualStyleBackColor = true; + // + // Docs + // + this.Docs.Controls.Add(this.buttonWordWithDiagram); + this.Docs.Controls.Add(this.buttonWordWithTable); + this.Docs.Controls.Add(this.buttonWordWithImage); + this.Docs.Location = new System.Drawing.Point(4, 29); + this.Docs.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Docs.Name = "Docs"; + this.Docs.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Docs.Size = new System.Drawing.Size(738, 588); + this.Docs.TabIndex = 1; + this.Docs.Text = "Docs"; + this.Docs.UseVisualStyleBackColor = true; + // + // buttonWordWithDiagram + // + this.buttonWordWithDiagram.Location = new System.Drawing.Point(490, 223); + this.buttonWordWithDiagram.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonWordWithDiagram.Name = "buttonWordWithDiagram"; + this.buttonWordWithDiagram.Size = new System.Drawing.Size(227, 97); + this.buttonWordWithDiagram.TabIndex = 13; + this.buttonWordWithDiagram.Text = "Word With Diagram"; + this.buttonWordWithDiagram.UseVisualStyleBackColor = true; + this.buttonWordWithDiagram.Click += new System.EventHandler(this.buttonWordWithDiagram_Click); + // + // buttonWordWithTable + // + this.buttonWordWithTable.Location = new System.Drawing.Point(256, 223); + this.buttonWordWithTable.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonWordWithTable.Name = "buttonWordWithTable"; + this.buttonWordWithTable.Size = new System.Drawing.Size(227, 97); + this.buttonWordWithTable.TabIndex = 14; + this.buttonWordWithTable.Text = "Word With Table"; + this.buttonWordWithTable.UseVisualStyleBackColor = true; + this.buttonWordWithTable.Click += new System.EventHandler(this.buttonWordWithTable_Click); + // + // buttonWordWithImage + // + this.buttonWordWithImage.Location = new System.Drawing.Point(22, 223); + this.buttonWordWithImage.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonWordWithImage.Name = "buttonWordWithImage"; + this.buttonWordWithImage.Size = new System.Drawing.Size(227, 97); + this.buttonWordWithImage.TabIndex = 13; + this.buttonWordWithImage.Text = "Word With Image"; + this.buttonWordWithImage.UseVisualStyleBackColor = true; + this.buttonWordWithImage.Click += new System.EventHandler(this.buttonWordWithImage_Click); + // + // FormMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(771, 648); + this.Controls.Add(this.tabControl); + this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.Name = "FormMain"; + this.Text = "FormMain"; + this.groupBoxInput.ResumeLayout(false); + this.groupBoxInput.PerformLayout(); + this.groupBoxSelected.ResumeLayout(false); + this.groupBoxSelected.PerformLayout(); + this.groupBoxData.ResumeLayout(false); + this.groupBoxData.PerformLayout(); + this.tabControl.ResumeLayout(false); + this.Visual.ResumeLayout(false); + this.Docs.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private MyCustomComponents.CustomInputRangeNumber customInputRangeNumber; + private TextBox textBoxMin; + private TextBox textBoxMax; + private Button buttonCheck; + private Label labelCheckValue; + private GroupBox groupBoxInput; + private GroupBox groupBoxSelected; + private Button buttonGetSelected; + private Label labelSelectedValue; + private Button buttonClear; + private Button buttonAdd; + private TextBox textBoxAdd; + private MyCustomComponents.CustomSelectedCheckedListBoxProperty customSelectedCheckedListBoxProperty; + private GroupBox groupBoxData; + private MyCustomComponents.CustomTreeView customTreeView; + private Button buttonGetFromTree; + private Button buttonAddToTree; + private ComboBox comboBoxDeviceType; + private TextBox textBoxModel; + private TextBox textBoxSerialNumber; + private Label labelDeviceType; + private Label labelModel; + private Label labelRegNum; + private TabControl tabControl; + private TabPage Visual; + private TabPage Docs; + private Button buttonWordWithImage; + private MyCustomComponents.WordWithImages wordWithImages; + private Button buttonWordWithTable; + private MyCustomComponents.WordWithTable wordWithTable; + private Button buttonWordWithDiagram; + private MyCustomComponents.WordWithDiagram wordWithDiagram; + } +} \ No newline at end of file diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.cs b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.cs new file mode 100644 index 0000000..c24da68 --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.cs @@ -0,0 +1,255 @@ +using MyCustomComponents; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace DesktopWithMyVisualComponents +{ + public partial class FormMain : Form + { + readonly List devices = new() + { + new Device { Id = 1, SerialNumber = "SM-12345", DeviceType = "Мобильный телефон", Model = "IPhone 13", Owner = "Иван Иванов", PurchaseDate = new DateTime(2022, 5, 15), State = "Новый", Price = 70000, Color = "Синий", WarrantyPeriod = 6 }, + new Device { Id = 2, SerialNumber = "CO2UD8471", DeviceType = "Ноутбук", Model = "MacBook Pro", Owner = "Петр Петров", PurchaseDate = new DateTime(2021, 3, 20), State = "Б/У", Price = 150000, Color = "Черный", WarrantyPeriod = 12 }, + new Device { Id = 3, SerialNumber = "R80NZD8812", DeviceType = "Умные часы", Model = "Galaxy Watch 4", Owner = "Анна Смирнова", PurchaseDate = new DateTime(2023, 1, 10), State = "Новый", Price = 25000, Color = "Белый", WarrantyPeriod = 18 }, + new Device { Id = 4, SerialNumber = "SM-G3412", DeviceType = "Мобильный телефон", Model = "Samsung Galaxy S24", Owner = "Елена Кузнецова", PurchaseDate = new DateTime(2023, 7, 25), State = "Новый", Price = 80000, Color = "Синий", WarrantyPeriod = 6 }, + new Device { Id = 5, SerialNumber = "FN738214", DeviceType = "Умные часы", Model = "Apple Watch 3", Owner = "Дмитрий Федоров", PurchaseDate = new DateTime(2020, 8, 5), State = "Б/У", Price = 15000, Color = "Красный", WarrantyPeriod = 24 }, + }; + + public FormMain() + { + InitializeComponent(); + + // Пример для компонента + var list = new List() { "Значение 1", "Значение 2", "Значение 3", "Значение 4", "Значение 5" }; + customSelectedCheckedListBoxProperty.Items.AddRange(list.ToArray()); + + comboBoxDeviceType.Items.Add("Мобильный телефон"); + comboBoxDeviceType.Items.Add("Ноутбук"); + comboBoxDeviceType.Items.Add("Умные часы"); + + // Загрузка дерева с девайсами + LoadTree(); + + customTreeView.SelectedTreeNode = 2; + + // Присоединить обработчик события при изменении значения + customInputRangeNumber.ChangeEvent += CustomInputRangeNumber_ChangeEvent; + } + + // Загрузка дерево с иерархией устройств на основе типа устройства, модели и серийного номера + public void LoadTree() + { + // Очистите существующие узлы перед загрузкой новых + customTreeView.Clear(); + + customTreeView.hierarchy = new List { "DeviceType", "Model", "SerialNumber" }; + + foreach (Device device in devices) + { + customTreeView.AddNode(device, "SerialNumber"); + } + } + + // Вынесенная логика проверки значения + private void UpdateLabelWithValue() + { + labelCheckValue.Text = customInputRangeNumber.Value.ToString(); + if (string.IsNullOrEmpty(labelCheckValue.Text)) + { + labelCheckValue.Text = customInputRangeNumber.Error; + } + } + + // Добавляем метод для обработки изменения значения + private void CustomInputRangeNumber_ChangeEvent(object sender, EventArgs e) + { + UpdateLabelWithValue(); + } + + // Метод проверки значения в Input + private void buttonCheck_Click(object sender, EventArgs e) + { + UpdateLabelWithValue(); + } + + // Установка границ + private void buttonSetBorders_Click(object sender, EventArgs e) + { + if (decimal.TryParse(textBoxMin.Text, out decimal minValue) && decimal.TryParse(textBoxMax.Text, out decimal maxValue)) + { + // Проверка: MaxValue должно быть больше MinValue + if (maxValue <= minValue) + { + labelCheckValue.Text = "Ошибка: MaxValue должно быть больше MinValue."; + return; + } + + // Устанавливаем границы + customInputRangeNumber.MinValue = minValue; + customInputRangeNumber.MaxValue = maxValue; + labelCheckValue.Text = "Границы установлены"; + + // Проверим текущее значение компонента на соответствие новому диапазону + /*try + { + var currentValue = customInputRangeNumber.Value; + + // Если значение в пределах, выводим сообщение об успехе + labelCheckValue.Text = "Границы установлены. Текущее значение в пределах диапазона."; + } + catch (ArgumentOutOfRangeException ex) + { + // Если текущее значение вне диапазона, выводим ошибку + labelCheckValue.Text = $"Ошибка: {ex.Message}"; + }*/ + } + else + { + labelCheckValue.Text = "Ошибка: неверные значения границ"; + } + } + + private void textBoxMin_KeyPress(object sender, KeyPressEventArgs e) + { + char ch = e.KeyChar; + + if (!Char.IsDigit(ch) && ch != 8 && ch != 45) + { + e.Handled = true; + } + } + + private void textBoxMax_KeyPress(object sender, KeyPressEventArgs e) + { + char ch = e.KeyChar; + + if (!Char.IsDigit(ch) && ch != 8 && ch != 45) + { + e.Handled = true; + } + } + + private void buttonAdd_Click(object sender, EventArgs e) + { + if (textBoxAdd.Text != "" && !customSelectedCheckedListBoxProperty.Items.Contains(textBoxAdd.Text)) + customSelectedCheckedListBoxProperty.Items.Add(textBoxAdd.Text); + else if (customSelectedCheckedListBoxProperty.Items.Contains(textBoxAdd.Text)) + customSelectedCheckedListBoxProperty.SelectedElement = textBoxAdd.Text; + } + + private void buttonClear_Click(object sender, EventArgs e) + { + customSelectedCheckedListBoxProperty.Clear(); + } + + private void buttonGetSelected_Click(object sender, EventArgs e) + { + labelSelectedValue.Text = customSelectedCheckedListBoxProperty.SelectedElement; + if (string.IsNullOrEmpty(labelSelectedValue.Text)) + { + labelSelectedValue.Text = "Значение \nне выбрано"; + } + } + + // Добавление нового узла в дерево + private void buttonAddToTree_Click(object sender, EventArgs e) + { + Device device = new Device + { + SerialNumber = textBoxSerialNumber.Text, + Model = textBoxModel.Text, + DeviceType = comboBoxDeviceType.SelectedItem?.ToString() + }; + + customTreeView.AddNode(device, "SerialNumber"); + } + + // Получение данных выбранного узла из дерева + private void buttonGetFromTree_Click(object sender, EventArgs e) + { + Device? device = customTreeView.GetSelectedNode(); + if (device == null) + { + return; + } + + textBoxSerialNumber.Text = device.SerialNumber; + textBoxModel.Text = device.Model; + comboBoxDeviceType.SelectedItem = device.DeviceType; + } + + private void buttonWordWithImage_Click(object sender, EventArgs e) + { + var openFileDialog = new OpenFileDialog(); + bool flag = true; + var images = new List(); + while (flag) + { + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + images.Add(File.ReadAllBytes(openFileDialog.FileName)); + } + else + { + flag = false; + } + } + wordWithImages.CreateDoc(new WordWithImageConfig + { + FilePath = "E:\\COP\\Lab 2\\WordWithImageDocx.docx", + Header = "Картинки:", + Images = images, + }); + } + + private void buttonWordWithTable_Click(object sender, EventArgs e) + { + wordWithTable.CreateDoc(new WordWithTableDataConfig + { + FilePath = "E:\\COP\\Lab 2\\WordWithTableDocx.docx", + Header = "Таблица:", + UseUnion = true, + ColumnsRowsWidth = new List<(int, int)> { (0, 5), (0, 5), (0, 10), (0, 10), (0, 7), (0, 7), (0, 10), (0, 10), (0, 8) }, + ColumnUnion = new List<(int StartIndex, int Count)> { (2, 3), (5, 3) }, + Headers = new List<(int ColumnIndex, int RowIndex, string Header, string PropertyName)> + { + (0, 0, "Номер", "Id"), + (1, 0, "Серийный номер", "SerialNumber"), + (2, 0, "Об устройстве", "DeviceType"), + (2, 1, "Модель", "Model"), + (3, 1, "Цвет", "Color"), + (4, 1, "Стоимость", "Price"), + (5, 0, "Покупатели", ""), + (5, 1, "Дата покупки", "PurchaseDate"), + (6, 1, "Владелец", "Owner"), + (7, 1, "Статус", "State"), + (8, 0, "Гарантия", "WarrantyPeriod"), + }, + Data = devices + }); + } + + private void buttonWordWithDiagram_Click(object sender, EventArgs e) + { + wordWithDiagram.CreateDoc(new WordWithDiagramConfig + { + FilePath = "E:\\COP\\Lab 2\\WordWithDiagramDocx.docx", + Header = "Диаграмма", + ChartTitle = "Круговая диаграмма", + LegendLocation = MyCustomComponents.Models.Location.Bottom, + Data = new Dictionary> + { + { "Серия 1", new List<(int Date, double Value)> { (1, 20), (2, 30), (3, 50) } } + } + }); + } + } +} diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.resx b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.resx new file mode 100644 index 0000000..93c550b --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/FormMain.resx @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 161, 17 + + + 295, 17 + + \ No newline at end of file diff --git a/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Program.cs b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Program.cs new file mode 100644 index 0000000..7aba605 --- /dev/null +++ b/Lab 2/Belianin_2/DesktopWithMyVisualComponents/Program.cs @@ -0,0 +1,17 @@ +namespace DesktopWithMyVisualComponents +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new FormMain()); + } + } +} \ No newline at end of file diff --git a/Lab 2/Belianin_2/MyCustomComponents/Attributes/AlwaysCreateAttribute .cs b/Lab 2/Belianin_2/MyCustomComponents/Attributes/AlwaysCreateAttribute .cs new file mode 100644 index 0000000..db0392f --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Attributes/AlwaysCreateAttribute .cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Attributes +{ + public class AlwaysCreateAttribute : Attribute + { + public AlwaysCreateAttribute() { } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.Designer.cs new file mode 100644 index 0000000..afbf042 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.Designer.cs @@ -0,0 +1,59 @@ +namespace MyCustomComponents +{ + partial class CustomInputRangeNumber + { + /// + /// Обязательная переменная конструктора. + /// + 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() + { + numericUpDown = new NumericUpDown(); + ((System.ComponentModel.ISupportInitialize)numericUpDown).BeginInit(); + SuspendLayout(); + // + // numericUpDown + // + numericUpDown.Location = new Point(3, 2); + numericUpDown.Margin = new Padding(3, 2, 3, 2); + numericUpDown.Name = "numericUpDown"; + numericUpDown.Size = new Size(131, 23); + numericUpDown.TabIndex = 0; + // + // CustomInputRangeNumber + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(numericUpDown); + Margin = new Padding(3, 2, 3, 2); + Name = "CustomInputRangeNumber"; + Size = new Size(141, 27); + ((System.ComponentModel.ISupportInitialize)numericUpDown).EndInit(); + ResumeLayout(false); + } + + #endregion + + private NumericUpDown numericUpDown; + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.cs new file mode 100644 index 0000000..e3da2f6 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.cs @@ -0,0 +1,122 @@ +using MyCustomComponents.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace MyCustomComponents +{ + public partial class CustomInputRangeNumber : UserControl + { + // Диапазон + private string example = "Введите значение от " + decimal.MinValue + " до " + decimal.MaxValue; + + // В случае ошибки + public string Error { get; protected set; } = string.Empty; + + // Создам 2 публичных поля для настройки границ диапазона + public decimal? MinValue { get; set; } = null; + public decimal? MaxValue { get; set; } = null; + + + /* Публичное свойство для установки и получения введённого значения (set, get). При получении проводится проверка, + Если введённое значение не входит в диапозон, возвращать значение null, а в отдельное поле выводить текст ошибки. + При установке должна проводиться проверка, если передаваемое значение не входит в диапозон, то не заполнять поле компонента. + */ + + public decimal? Value + { + get + { + // Как мы проверим что программист не забыл задать минимальное, максимальное значение? + // Проверка, что MinValue и MaxValue задан + if (!MinValue.HasValue || !MaxValue.HasValue) + { + throw new RangeException("MinValue и MaxValue должны быть заданы."); + } + + // Проверяем, что max не может быть min + if (MaxValue.Value <= MinValue.Value) + { + throw new RangeException("MaxValue должно быть больше MinValue"); + } + + decimal currentValue = numericUpDown.Value; + + // Проверка, что значение в диапазоне + if (currentValue < MinValue.Value || currentValue > MaxValue.Value) + { + throw new RangeException($"Введённое значение {currentValue} лежит вне диапазона {MinValue.Value} - {MaxValue.Value}."); + } + + return currentValue; + } + set + { + // Проверка, что MinValue и MaxValue заданы + if (!MinValue.HasValue || !MaxValue.HasValue) + { + Error = "MinValue и MaxValue должны быть заданы."; + return; + } + + // Проверка, что MinValue меньше MaxValue + if (MinValue.Value >= MaxValue.Value) + { + Error = "Диапазон неверен. MinValue должен быть меньше, чем MaxValue."; + return; + } + + // Если число верно в диапозоне, то значение устанавливается + if (value.HasValue && value.Value >= MinValue.Value && value.Value <= MaxValue.Value) + { + numericUpDown.Value = value.Value; + + // Очистить ошибку, если значение установлено успешно + Error = null; + } + else + { + Error = $"Значение должно быть в диапазоне от {MinValue.Value} до {MaxValue.Value}."; + } + } + } + + + public CustomInputRangeNumber() + { + InitializeComponent(); + } + + private void numericUpDown_Enter(object sender, EventArgs e) + { + ToolTip toolTip = new ToolTip(); + toolTip.Show(example, numericUpDown, 30, -20, 1000); + } + + private void numericUpDown_ValueChanged(object sender, EventArgs e) + { + _changeEvent?.Invoke(sender, e); + } + + private EventHandler _changeEvent; + + // Событие, вызываемое при смене значения + public event EventHandler ChangeEvent + { + add + { + _changeEvent += value; + } + remove + { + _changeEvent -= value; + } + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.resx b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomInputRangeNumber.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.Designer.cs new file mode 100644 index 0000000..ca537d7 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.Designer.cs @@ -0,0 +1,56 @@ +namespace MyCustomComponents +{ + partial class CustomSelectedCheckedListBoxProperty + { + /// + /// Обязательная переменная конструктора. + /// + 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() + { + checkedListBox = new CheckedListBox(); + SuspendLayout(); + // + // checkedListBox + // + checkedListBox.FormattingEnabled = true; + checkedListBox.Location = new Point(4, 4); + checkedListBox.Name = "checkedListBox"; + checkedListBox.Size = new Size(164, 180); + checkedListBox.TabIndex = 0; + // + // CustomSelectedCheckedListBoxProperty + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(checkedListBox); + Name = "CustomSelectedCheckedListBoxProperty"; + Size = new Size(171, 209); + ResumeLayout(false); + } + + #endregion + + private CheckedListBox checkedListBox; + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.cs new file mode 100644 index 0000000..43999dd --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.cs @@ -0,0 +1,89 @@ +using MyCustomComponents.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace MyCustomComponents +{ + public partial class CustomSelectedCheckedListBoxProperty : UserControl + { + /* Публичное свойство, которое передаёт ссылку на свойство Items + * элемента ComboBox, через которое и идёт заполнение */ + public CheckedListBox.ObjectCollection Items => checkedListBox.Items; + + public CustomSelectedCheckedListBoxProperty() + { + InitializeComponent(); + } + + // Отдельный публичный метод очистки списка + public void Clear() + { + checkedListBox.Items.Clear(); + } + + private EventHandler _changeEvent; + + private void checkedListBox_SelectedIndexChanged(object sender, EventArgs e) + { + _changeEvent?.Invoke(sender, e); + } + + // Событие, вызываемое при смене значения в CheckedListBox + public event EventHandler Changed + { + add + { + _changeEvent += value; + } + remove + { + _changeEvent -= value; + } + } + + + // Публичное свойство (set, get) для установки и получения выбранного значения (возвращает пустую строку, если нет выбранного значения) + public string SelectedElement + { + get + { + return (checkedListBox.SelectedIndex > -1 && checkedListBox.GetItemChecked(checkedListBox.SelectedIndex)) ? checkedListBox.SelectedIndex.ToString() : string.Empty; + } + set + { + if (!string.IsNullOrEmpty(value)) + { + int index = checkedListBox.Items.IndexOf(value); + + // Если попытаться установить несуществующий элемент + if (index == -1) + { + // Выбрасываем исключение, если элемент не найден в списке + throw new InvalidSelectedElementException($"Элемент '{value}' не найден в списке."); + } + + checkedListBox.SelectedItem = value; + checkedListBox.SetItemCheckState(checkedListBox.SelectedIndex, CheckState.Checked); + } + } + } + + + private void checkedListBox_ItemCheck(object sender, ItemCheckEventArgs e) + { + if (e.NewValue == CheckState.Checked && checkedListBox.CheckedItems.Count > 0) + { + checkedListBox.ItemCheck -= checkedListBox_ItemCheck; + checkedListBox.SetItemChecked(checkedListBox.CheckedIndices[0], value: false); + checkedListBox.ItemCheck += checkedListBox_ItemCheck; + } + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.resx b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomSelectedCheckedListBoxProperty.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.Designer.cs new file mode 100644 index 0000000..35784f9 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.Designer.cs @@ -0,0 +1,55 @@ +namespace MyCustomComponents +{ + partial class CustomTreeView + { + /// + /// Обязательная переменная конструктора. + /// + 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() + { + treeView = new TreeView(); + SuspendLayout(); + // + // treeView + // + treeView.Location = new Point(3, 3); + treeView.Name = "treeView"; + treeView.Size = new Size(517, 259); + treeView.TabIndex = 0; + // + // CustomTreeCell + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(treeView); + Name = "CustomTreeCell"; + Size = new Size(525, 269); + ResumeLayout(false); + } + + #endregion + + private TreeView treeView; + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.cs b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.cs new file mode 100644 index 0000000..df80615 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.cs @@ -0,0 +1,168 @@ +using MyCustomComponents.Extensions; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button; +using static System.Windows.Forms.VisualStyles.VisualStyleElement; +using MyCustomComponents.Attributes; +using System.Xml.Linq; + +namespace MyCustomComponents +{ + public partial class CustomTreeView : UserControl + { + public CustomTreeView() + { + InitializeComponent(); + } + + // Свойство для получения и установки выбранного узла в TreeView + public int SelectedTreeNode + { + get + { + if (treeView.SelectedNode != null) + { + return treeView.SelectedNode.Index; + } + + return -1; + } + set + { + if (treeView.Nodes.Count > 0 && value >= 0 && value < treeView.Nodes.Count) + { + treeView.SelectedNode = treeView.Nodes[value]; + } + else + { + throw new ArgumentOutOfRangeException(nameof(value), $"Индекс {value} выходит за пределы допустимого диапазона. Допустимый диапазон: от 0 до {treeView.Nodes.Count - 1}."); + } + } + } + + public List? hierarchy { get; set; } + + private Dictionary newBranch { get; set; } = new Dictionary(); + + // Отдельный публичный метод очистки всех узлов дерева + public void Clear() + { + treeView.Nodes.Clear(); + } + + // Публичный метод для получения выбранной записи из древовидной структуры + public T GetSelectedNode() where T : class, new() + { + if (hierarchy == null) + { + throw new HierarchyNullException("Hierarchy is null"); + } + + if (treeView.SelectedNode == null) + { + throw new InvalidSelectedElementException("TreeView null"); + } + + // Проверка, является ли выбранный узел корневым + if (treeView.SelectedNode.Parent == null) + { + // Выбран корневой элемент — возвращаем пустой объект + throw new InvalidSelectedElementException("Parent is null"); + } + + // Если узел выбран и существует, вызываем приватный метод для получения данных узла + return _getNode(); + } + + + // Приватный метод, идущий по узлам вверх (по иерархии) + private T _getNode() where T : new() + { + TreeNode? node = treeView.SelectedNode; + + var obj = new T(); + int level = hierarchy.Count - 1; + + // Проходим по иерархии от нижнего уровня к верхнему + while (node != null && level >= 0) + { + var property = hierarchy[level]; + obj.GetType().GetProperty(property)?.SetValue(obj, node.Text); + + node = node.Parent; + + level--; + } + + return obj; + } + + /* Параметризированный метод, у которого в передаваемых параметрах + * идёт объект какого-то класса и имя свойства/поля, до которого согласно + * иерархии будет следовать формирование ветви + */ + public void AddNode(T obj, string propertyName) + { + if (hierarchy == null) + { + throw new HierarchyNullException("Hierarchy is null"); + } + + if (obj == null) + { + throw new ArgumentNullException("Added object is null"); + } + + // Получаем первый узел в дереве + TreeNode currentNode = null; + + // Проходимся по иерархии + foreach (var property in hierarchy) + { + // Получаем значение свойства + var value = obj.GetType().GetProperty(property)?.GetValue(obj, null)?.ToString(); + bool createNewBranch = newBranch != null && newBranch.ContainsKey(propertyName) && newBranch[propertyName]; + + if (currentNode == null) + { + currentNode = treeView.Nodes.Cast().FirstOrDefault(n => n.Text == value) + ?? treeView.Nodes.Add(value); + } + else + { + var childNode = currentNode.Nodes.Cast().FirstOrDefault(n => n.Text == value); + + // Проверка нужно ли нам создавать дочерний узел + if (childNode == null || createNewBranch) + { + childNode = currentNode.Nodes.Add(value); + } + + // Переходим на уровень этого дочернего узла + currentNode = childNode; + } + + if (property == propertyName) + { + break; + } + + } + } + + + public void SetHierarchy(List hierarchy, Dictionary newBranch) + { + this.hierarchy = hierarchy; + this.newBranch = newBranch; + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.resx b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/CustomTreeView.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Lab 2/Belianin_2/MyCustomComponents/Extensions/HierarchyNullException.cs b/Lab 2/Belianin_2/MyCustomComponents/Extensions/HierarchyNullException.cs new file mode 100644 index 0000000..1699429 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Extensions/HierarchyNullException.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Extensions +{ + public class HierarchyNullException : Exception + { + public HierarchyNullException() { } + + public HierarchyNullException(string message) : base(message) { } + + public HierarchyNullException(string message, Exception inner) : base(message, inner) { } + + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Extensions/InvalidSelectedElementException.cs b/Lab 2/Belianin_2/MyCustomComponents/Extensions/InvalidSelectedElementException.cs new file mode 100644 index 0000000..f5b0986 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Extensions/InvalidSelectedElementException.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Extensions +{ + // Исключение, если нет выбранного и отмеченного элемента + public class InvalidSelectedElementException : Exception + { + public InvalidSelectedElementException() { } + + public InvalidSelectedElementException(string message) : base(message) + { + } + + public InvalidSelectedElementException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Extensions/PropertyNullException.cs b/Lab 2/Belianin_2/MyCustomComponents/Extensions/PropertyNullException.cs new file mode 100644 index 0000000..0de8cea --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Extensions/PropertyNullException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Extensions +{ + public class PropertyNullException : Exception + { + public PropertyNullException() { } + + public PropertyNullException(string message) : base(message) { } + + public PropertyNullException(string message, Exception inner) : base(message, inner) { } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Extensions/RangeException.cs b/Lab 2/Belianin_2/MyCustomComponents/Extensions/RangeException.cs new file mode 100644 index 0000000..aa8e00c --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Extensions/RangeException.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Extensions +{ + internal class RangeException : Exception + { + public RangeException() { } + + public RangeException(string message) : base(message) + { } + + public RangeException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Extensions/ValueOutOfRangeException .cs b/Lab 2/Belianin_2/MyCustomComponents/Extensions/ValueOutOfRangeException .cs new file mode 100644 index 0000000..91e3b33 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Extensions/ValueOutOfRangeException .cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Extensions +{ + // Ошибка неверного значения, когда значение выходит за границы диапазона + public class ValueOutOfRangeException : Exception + { + public ValueOutOfRangeException() { } + + public ValueOutOfRangeException(string message) : base(message) + { + } + + public ValueOutOfRangeException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/CreatorDiagram.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/CreatorDiagram.cs new file mode 100644 index 0000000..f147081 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/CreatorDiagram.cs @@ -0,0 +1,289 @@ +using DocumentFormat.OpenXml; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml.Drawing.Charts; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Helpers +{ + // Класс CreatorDiagram отвечает за создание диаграмм + public class CreatorDiagram + { + // Порядок и индекс используются для нумерации серий на диаграмме + private static uint order = 0u; + + private static uint index = 1u; + + // Метод GeneratePieChart генерирует круговую диаграмму на основе конфигурации + public static DocumentFormat.OpenXml.Drawing.Charts.Chart GeneratePieChart(WordWithDiagramConfig config) + { + // Создаем объект PieChart + PieChart pieChart = new PieChart(); + + // Добавляем первую серию данных в диаграмму + pieChart.Append(GeneratePieChartSeries(config.Data.First().Key, config.Data.First().Value)); + + // Создаем область построения (PlotArea) для диаграммы + // Добавляем макет для более гибкого управления размещением элементов. Добавляем круговую диаграмму в область построения + PlotArea plotArea = new PlotArea(); + plotArea.Append(new Layout()); + plotArea.Append(pieChart); + + // Возвращаем объект диаграммы с заголовком и расположением легенды + return GenerateChart(config.ChartTitle, plotArea, config.LegendLocation); + } + + private static DocumentFormat.OpenXml.Drawing.Charts.Chart GenerateChart(string titleText, PlotArea plotArea, Location legendLocation) + { + DocumentFormat.OpenXml.Drawing.Charts.Chart chart = new DocumentFormat.OpenXml.Drawing.Charts.Chart(); + + // Проверяем текст заголовка и добавляем его + if (titleText.HaveText()) + { + chart.Append(GenerateTitle(titleText)); + } + else + { + chart.Append(new AutoTitleDeleted + { + Val = (BooleanValue)true + }); + } + + // Определяем позицию легенды на основе переданного значения + LegendPositionValues position = legendLocation switch + { + Location.Top => LegendPositionValues.Top, + Location.Right => LegendPositionValues.Right, + Location.Left => LegendPositionValues.Left, + _ => LegendPositionValues.Bottom, + }; + + // Добавляем область построения и легенду к диаграмме + chart.Append(plotArea); + chart.Append(GenerateLegend(position)); + + // Устанавливаем видимость только для отображаемых данных + chart.Append(new PlotVisibleOnly + { + Val = (BooleanValue)true + }); + + return chart; + } + + // Метод создает объект легенды для диаграммы + private static Legend GenerateLegend(LegendPositionValues position) + { + // Свойства текста для легенды + ParagraphProperties paragraphProperties = new ParagraphProperties(); + paragraphProperties.Append(new DefaultRunProperties()); + + Paragraph paragraph = new Paragraph(); + paragraph.Append(paragraphProperties); + paragraph.Append(new EndParagraphRunProperties()); + + TextProperties textProperties = new TextProperties(); + textProperties.Append(new BodyProperties()); + textProperties.Append(new ListStyle()); + textProperties.Append(paragraph); + + // Создаем объект легенды с заданной позицией + Legend legend = new Legend(); + legend.Append(new LegendPosition + { + Val = (EnumValue)position + }); + + legend.Append(new Layout()); + legend.Append(new Overlay + { + Val = (BooleanValue)false + }); + + // Добавляем свойства текста к легенде + legend.Append(textProperties); + + return legend; + } + + // Метод создает объект заголовка для диаграммы + private static Title GenerateTitle(string titleText) + { + // Создаем объект Run для текста заголовка + Run run = new Run(); + run.Append(new RunProperties + { + FontSize = (Int32Value)1100 + }); + + run.Append(new Text(titleText)); // Добавялем текст заголовка + + // Свойства абзаца для заголовка + ParagraphProperties paragraphProperties = new ParagraphProperties(); + paragraphProperties.Append(new DefaultRunProperties + { + FontSize = (Int32Value)1100 + }); + + Paragraph paragraph = new Paragraph(); + paragraph.Append(paragraphProperties); + paragraph.Append(run); + + // Создаем RichText, чтобы включить заголовок в диаграмму + RichText richText = new RichText(); + richText.Append(new BodyProperties()); + richText.Append(new ListStyle()); + richText.Append(paragraph); + + ChartText chartText = new ChartText(); + chartText.Append(richText); + + // Создаем объект Title, содержащий текст заголовка + Title title = new Title(); + title.Append(chartText); + title.Append(new Layout()); // Добавляем макет + + // Производим наложение + title.Append(new Overlay + { + Val = (BooleanValue)false + }); + + return title; + } + + // Метод создает текст для серий данных + private static SeriesText GenerateSeriesText(string seriesName) + { + StringPoint stringPoint = new StringPoint + { + Index = (UInt32Value)0u + }; + + stringPoint.Append(new NumericValue + { + Text = seriesName + }); + + // Кэш строковых значений + StringCache stringCache = new StringCache(); + stringCache.Append(new PointCount + { + Val = (UInt32Value)1u + }); + + stringCache.Append(stringPoint); + + StringReference stringReference = new StringReference(); + stringReference.Append(stringCache); + + SeriesText seriesText = new SeriesText(); + seriesText.Append(stringReference); + + return seriesText; + } + + // Метод создает данные оси категорий + private static CategoryAxisData GenerateCategoryAxisData(string[] data) + { + uint number = (uint)data.Length; + NumberingCache numberingCache = GenerateNumberingCache(number); + + for (uint number2 = 0u; number2 < number; number2++) + { + numberingCache.Append(GenerateNumericPoint(number2, data[number2].ToString())); + } + + NumberReference numberReference = new NumberReference(); + numberReference.Append(numberingCache); + + CategoryAxisData categoryAxisData = new CategoryAxisData(); + categoryAxisData.Append(numberReference); + + return categoryAxisData; + } + + // Метод создает объект значений для диаграммы + private static Values GenerateValues(double[] data) + { + uint number = (uint)data.Length; + NumberingCache numberingCache = GenerateNumberingCache(number); + + for (uint number2 = 0u; number2 < number; number2++) + { + numberingCache.Append(GenerateNumericPoint(number2, data[number2].ToString())); + } + + NumberReference numberReference = new NumberReference(); + numberReference.Append(numberingCache); + + Values values = new Values(); + values.Append(numberReference); + + return values; + } + + // Метод создает кэш для числовых данных + private static NumberingCache GenerateNumberingCache(uint numberPoints) + { + NumberingCache numberingCache = new NumberingCache(); + numberingCache.Append(new FormatCode + { + Text = "General" + }); + + numberingCache.Append(new PointCount + { + Val = (UInt32Value)numberPoints + }); + + return numberingCache; + } + + // Метод создает числовую точку данных + private static NumericPoint GenerateNumericPoint(UInt32Value idx, string text) + { + NumericPoint numericPoint = new NumericPoint + { + Index = idx + }; + numericPoint.Append(new NumericValue + { + Text = text + }); + + return numericPoint; + } + + // Метод создает серию данных для круговой диаграммы + private static PieChartSeries GeneratePieChartSeries(string seriesName, List<(int Date, double Value)> data) + { + // Создаем объект серии для круговой диаграммы + PieChartSeries pieChartSeries = new PieChartSeries(); + pieChartSeries.Append(new DocumentFormat.OpenXml.Drawing.Charts.Index + { + Val = (UInt32Value)index + }); + pieChartSeries.Append(new Order + { + Val = (UInt32Value)order + }); + + // Добавляем текст серии, данные оси категорий и значения + pieChartSeries.Append(GenerateSeriesText(seriesName)); + pieChartSeries.Append(GenerateCategoryAxisData(data.Select(((int Date, double Value) c) => c.Date.ToString()).ToArray())); + pieChartSeries.Append(GenerateValues(data.Select(((int Date, double Value) v) => v.Value).ToArray())); + + index++; + order++; + + return pieChartSeries; + } + + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/DiagramService.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/DiagramService.cs new file mode 100644 index 0000000..05faa9d --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/DiagramService.cs @@ -0,0 +1,157 @@ +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml; +using MyCustomComponents.Models; +using System; +using DocumentFormat.OpenXml.Drawing.Wordprocessing; +using DocumentFormat.OpenXml.Wordprocessing; + +namespace MyCustomComponents.Helpers +{ + public class DiagramService + { + // Хранит документ Word + private Document _document = null; + + // Хранит тело документа Word + private Body _body = null; + + // Хранит диаграмму (график), которая будет добавлена в документ + private DocumentFormat.OpenXml.Drawing.Charts.Chart _chart; + + // Свойство для создания или получения документа + private Document Document + { + get + { + if (_document == null) + { + _document = new Document(); + } + + return _document; + } + } + + // Свойство для создания или получения тела документа + private Body Body + { + get + { + if (_body == null) + { + _body = Document.AppendChild(new Body()); + } + + return _body; + } + } + + public DiagramService() + { + _document = new Document(); + _body = _document.AppendChild(new Body()); + } + + // Метод для создания документа с диаграммой + public void CreateHeader(string header) + { + DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph = Body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph()); + DocumentFormat.OpenXml.Wordprocessing.Run run = paragraph.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Run()); + + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties(new Bold())); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(header)); + } + + public void SaveDoc(string filepath) + { + if (filepath.IsEmpty()) + { + throw new ArgumentNullException("Имя файла не задано"); + } + + if (_document == null || _body == null) + { + throw new ArgumentNullException("Документ не сформирован, сохранять нечего"); + } + + using WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document); + MainDocumentPart mainDocumentPart = wordprocessingDocument.AddMainDocumentPart(); + mainDocumentPart.Document = Document; + + if (_chart != null) + { + ChartPart chartPart = mainDocumentPart.AddNewPart("rId110"); + ChartSpace chartSpace = new ChartSpace(); + chartSpace.Append(new EditingLanguage + { + Val = (StringValue)"en-us" + }); + + chartSpace.Append(_chart); + ChartShapeProperties chartShapeProperties = new ChartShapeProperties(); + DocumentFormat.OpenXml.Drawing.Outline outline = new DocumentFormat.OpenXml.Drawing.Outline(); + + outline.Append(new NoFill()); + chartShapeProperties.Append(outline); + chartSpace.Append(chartShapeProperties); + chartPart.ChartSpace = chartSpace; + + GeneratePartContent(mainDocumentPart); + } + } + + private static void GeneratePartContent(MainDocumentPart mainPart) + { + DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph + { + RsidParagraphAddition = (HexBinaryValue)"00C75AEB", + RsidRunAdditionDefault = (HexBinaryValue)"000F3EFF" + }; + + DocumentFormat.OpenXml.Wordprocessing.Run run = new DocumentFormat.OpenXml.Wordprocessing.Run(); + Drawing drawing = new Drawing(); + Inline inline = new Inline(); + + inline.Append(new Extent + { + Cx = (Int64Value)5274310L, + Cy = (Int64Value)3076575L + }); + + DocProperties docProperties = new DocProperties + { + Id = (UInt32Value)1u, + Name = (StringValue)"Chart 1" + }; + + inline.Append(docProperties); + Graphic graphic = new Graphic(); + + GraphicData graphicData = new GraphicData + { + Uri = (StringValue)"http://schemas.openxmlformats.org/drawingml/2006/chart" + }; + + ChartReference chartReference = new ChartReference + { + Id = (StringValue)"rId110" + }; + + graphicData.Append(chartReference); + graphic.Append(graphicData); + inline.Append(graphic); + drawing.Append(inline); + + run.Append(drawing); + paragraph.Append(run); + mainPart.Document.Body!.Append(paragraph); + } + + public void CreatePieChart(WordWithDiagramConfig config) + { + _chart = CreatorDiagram.GeneratePieChart(config); + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionConfig.cs new file mode 100644 index 0000000..5cf0531 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionConfig.cs @@ -0,0 +1,210 @@ +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Helpers +{ + public static class ExtensionConfig + { + // Проверяет поля в объекте WordConfig + public static void CheckFields(this WordConfig config) + { + if (config.FilePath.IsEmpty()) + { + throw new ArgumentNullException("Имя файла не задано"); + } + + if (config.Header.IsEmpty()) + { + throw new ArgumentNullException("Заголовок документа не задан"); + } + } + + // Проверяет поля в объекте WordWithDiagramConfig + public static void CheckFields(this WordWithDiagramConfig config) + { + // Используем метод проверки базового WordConfig + ((WordConfig)config).CheckFields(); + + if (config.ChartTitle.IsEmpty()) + { + throw new ArgumentNullException("Заголовок диаграммы не задан"); + } + + // Проверка на наличие данных для диаграммы + if (config.Data == null || config.Data.Count == 0 || config.Data.Any>> + ((KeyValuePair> x) => x.Key.IsEmpty() || x.Value == null || x.Value.Count == 0)) + { + throw new ArgumentNullException("Нет данных для заполнения диаграммы"); + } + } + + // Проверяет поля в объекте WordWithImageConfig + public static void CheckFields(this WordWithImageConfig config) + { + // Используем метод проверки базового WordConfig + ((WordConfig)config).CheckFields(); + + // Проверка на наличие изображений + if (config.Images == null || config.Images.Count == 0 || config.Images.All((byte[] x) => x == null || x.Length == 0)) + { + throw new ArgumentNullException("Нет изображений для вставки в документ"); + } + } + + // Универсальный метод проверки полей для WordWithTableDataConfig + public static void CheckFields(this WordWithTableDataConfig config) + { + WordWithTableDataConfig config2 = config; + + // Используем метод проверки базового WordConfig + ((WordConfig)config2).CheckFields(); + + // Проверка на наличие данных по ширине колонок + if (config2.ColumnsRowsWidth == null || config2.ColumnsRowsWidth.Count == 0) + { + throw new ArgumentNullException("Нет данных по ширине колонок таблицы"); + } + + // Проверка на наличие данных по объединению колонок (если используется объединение) + if (config2.UseUnion && (config2.ColumnUnion == null || config2.ColumnUnion.Count == 0)) + { + throw new ArgumentNullException("Нет данных по объединению колонок таблицы"); + } + + // Проверка заголовков таблицы + if (config2.Headers == null || config2.Headers.Count == 0 || config2.Headers.Any<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.Header.IsEmpty())) + { + throw new ArgumentNullException("Нет данных по заголовкам таблицы"); + } + + // Проверка на наличие данных для таблицы + if (config2.Data == null || config2.Data.Count == 0) + { + throw new ArgumentNullException("Нет данных для заполнения таблицы"); + } + + // Если объединение колонок не используется, выходим из метода + if (!config2.UseUnion) + { + return; + } + + // Проверка на выход объединения ячеек за границы таблицы + if (config2.ColumnsRowsWidth.Count < config2.ColumnUnion[config2.ColumnUnion.Count - 1].StartIndex + config2.ColumnUnion[config2.ColumnUnion.Count - 1].Count - 1) + { + throw new IndexOutOfRangeException("Последнее объединение ячеек выходит за границы таблицы"); + } + + // Проверка заголовков для колонок до объединений + int k; + for (k = 0; k < config2.ColumnUnion[0].StartIndex; k++) + { + int number = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == k).Count(); + if (number == 0) + { + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(34, 1); + defaultInterpolatedStringHandler.AppendLiteral("Для "); + defaultInterpolatedStringHandler.AppendFormatted(k); + defaultInterpolatedStringHandler.AppendLiteral(" колонки отсутствует заголовок"); + throw new ArgumentNullException(defaultInterpolatedStringHandler.ToStringAndClear()); + } + + if (number > 1) + { + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(37, 1); + defaultInterpolatedStringHandler.AppendLiteral("Для "); + defaultInterpolatedStringHandler.AppendFormatted(k); + defaultInterpolatedStringHandler.AppendLiteral(" колонки задано более 1 заголовка"); + throw new ArgumentNullException(defaultInterpolatedStringHandler.ToStringAndClear()); + } + } + + // Проверка объединений колонок на накладки + int j; + for (j = 0; j < config2.ColumnUnion.Count; j++) + { + if (j < config2.ColumnUnion.Count - 1 && config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count - 1 > config2.ColumnUnion[j + 1].StartIndex) + { + throw new IndexOutOfRangeException("Имеется накладка в объединении ячеек"); + } + + // Проверка заголовков для колонок 0 и 1 строк + int number2 = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex >= config2.ColumnUnion[j].StartIndex && x.ColumnIndex <= config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count - 1 && x.RowIndex == 0).Count(); + if (number2 == 0) + { + throw new ArgumentNullException("Для колонок 0 строки отсутствует заголовок"); + } + + if (number2 > 1) + { + throw new ArgumentNullException("Для колонок 0 строки задано более 1 заголовка"); + } + + number2 = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex >= config2.ColumnUnion[j].StartIndex && x.ColumnIndex <= config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count - 1 && x.RowIndex == 1).Count(); + if (number2 < config2.ColumnUnion[j].Count) + { + throw new ArgumentNullException("Для колонок 1 строки не хватает заголовков"); + } + + if (number2 > config2.ColumnUnion[j].Count) + { + throw new ArgumentNullException("Для колонок 1 строки задано более требуемого числа заголовков"); + } + + // Проверка заголовков для колонок между объединениями + if (j < config2.ColumnUnion.Count - 1) + { + number2 = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex >= config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count && x.ColumnIndex < config2.ColumnUnion[j + 1].StartIndex && x.RowIndex == 0).Count(); + + if (number2 < config2.ColumnUnion[j + 1].StartIndex - (config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count)) + { + throw new ArgumentNullException("Для колонок не хватает заголовков"); + } + + if (number2 > config2.ColumnUnion[j + 1].StartIndex - (config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count)) + { + throw new ArgumentNullException("Для колонок задано более требуемого числа заголовков"); + } + + number2 = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex >= config2.ColumnUnion[j].StartIndex + config2.ColumnUnion[j].Count && x.ColumnIndex < config2.ColumnUnion[j + 1].StartIndex && x.RowIndex == 1).Count(); + + if (number2 > 0) + { + throw new ArgumentNullException("Для колонок заданы заголовки 2 уровня, чего быть не должно"); + } + } + + // Проверка заголовков для оставшихся колонок после последнего объединения + int i; + + for (i = config2.ColumnUnion[config2.ColumnUnion.Count - 1].StartIndex + config2.ColumnUnion[config2.ColumnUnion.Count - 1].Count; i < config2.ColumnsRowsWidth.Count; i++) + { + int number3 = config2.Headers.Where<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == i).Count(); + + if (number3 == 0) + { + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(34, 1); + defaultInterpolatedStringHandler.AppendLiteral("Для "); + defaultInterpolatedStringHandler.AppendFormatted(i); + defaultInterpolatedStringHandler.AppendLiteral(" колонки отсутствует заголовок"); + throw new ArgumentNullException(defaultInterpolatedStringHandler.ToStringAndClear()); + } + + if (number3 > 1) + { + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(37, 1); + defaultInterpolatedStringHandler.AppendLiteral("Для "); + defaultInterpolatedStringHandler.AppendFormatted(i); + defaultInterpolatedStringHandler.AppendLiteral(" колонки задано более 1 заголовка"); + throw new ArgumentNullException(defaultInterpolatedStringHandler.ToStringAndClear()); + } + } + } + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionString.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionString.cs new file mode 100644 index 0000000..d1616e4 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ExtensionString.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Helpers +{ + public static class ExtensionString + { + public static bool HaveText(this string str) + { + return !string.IsNullOrEmpty(str); + } + + public static bool IsEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/ImageService.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ImageService.cs new file mode 100644 index 0000000..def59a4 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/ImageService.cs @@ -0,0 +1,209 @@ +using DocumentFormat.OpenXml.Drawing.Wordprocessing; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; + +namespace MyCustomComponents.Helpers +{ + public class ImageService + { + // Хранит документ Word + private Document _document = null; + + // Хранит тело документа Word + private Body _body = null; + + // Список байтовых массивов для изображений + private List _images = null; + + // Свойство для получения или создания документа Word + private Document Document + { + get + { + if (_document == null) + { + _document = new Document(); + } + + return _document; + } + } + + // Свойство для получения или создания тела документа Word + private Body Body + { + get + { + if (_body == null) + { + _body = Document.AppendChild(new Body()); + } + + return _body; + } + } + + // Свойство для получения списка изображений + private List Images + { + get + { + // Если список изображений еще не создан, инициализируем его + if (_images == null) + { + _images = new List(); + } + + return _images; + } + } + + public void CreateHeader(string header) + { + DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph = Body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph()); + DocumentFormat.OpenXml.Wordprocessing.Run run = paragraph.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Run()); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties(new Bold())); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(header)); + } + + public void CreateImage(byte[] image) + { + if (image == null || image.Length == 0) + { + throw new ArgumentNullException("Картинка не загружена"); + } + + Images.Add(image); + } + + public void SaveDoc(string filepath) + { + if (filepath.IsEmpty()) + { + throw new ArgumentNullException("Имя файла не задано"); + } + + if (_document == null || _body == null) + { + throw new ArgumentNullException("Документ не сформирован, сохранять нечего"); + } + + using WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document); + MainDocumentPart mainDocumentPart = wordprocessingDocument.AddMainDocumentPart(); + mainDocumentPart.Document = Document; + if (_images != null) + { + int num = 0; + foreach (byte[] image in _images) + { + ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Jpeg); + using (MemoryStream memoryStream = new MemoryStream(image)) + { + memoryStream.Position = 0L; + imagePart.FeedData(memoryStream); + } + + AddImageToBody(mainDocumentPart.GetIdOfPart(imagePart), ++num); + } + } + } + + private void AddImageToBody(string relationshipId, int index) + { + OpenXmlElement[] array = new OpenXmlElement[1]; + OpenXmlElement[] obj = new OpenXmlElement[5] + { + new Extent + { + Cx = (Int64Value)3000000L, + Cy = (Int64Value)3000000L + }, + new EffectExtent + { + LeftEdge = (Int64Value)0L, + TopEdge = (Int64Value)0L, + RightEdge = (Int64Value)0L, + BottomEdge = (Int64Value)0L + }, + null, + null, + null + }; + DocProperties obj2 = new DocProperties + { + Id = (UInt32Value)1u + }; + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(8, 1); + defaultInterpolatedStringHandler.AppendLiteral("Picture "); + defaultInterpolatedStringHandler.AppendFormatted(index); + obj2.Name = (StringValue)defaultInterpolatedStringHandler.ToStringAndClear(); + obj[2] = obj2; + obj[3] = new DocumentFormat.OpenXml.Drawing.Wordprocessing.NonVisualGraphicFrameDrawingProperties(new GraphicFrameLocks + { + NoChangeAspect = (BooleanValue)true + }); + OpenXmlElement[] array2 = new OpenXmlElement[1]; + OpenXmlElement[] array3 = new OpenXmlElement[1]; + OpenXmlElement[] array4 = new OpenXmlElement[3]; + OpenXmlElement[] array5 = new OpenXmlElement[2]; + DocumentFormat.OpenXml.Drawing.Pictures.NonVisualDrawingProperties obj3 = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualDrawingProperties + { + Id = (UInt32Value)0u + }; + defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(16, 1); + defaultInterpolatedStringHandler.AppendLiteral("New Picture "); + defaultInterpolatedStringHandler.AppendFormatted(index); + defaultInterpolatedStringHandler.AppendLiteral(".jpg"); + obj3.Name = (StringValue)defaultInterpolatedStringHandler.ToStringAndClear(); + array5[0] = obj3; + array5[1] = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureDrawingProperties(); + array4[0] = new DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureProperties(array5); + array4[1] = new DocumentFormat.OpenXml.Drawing.Pictures.BlipFill(new Blip(new BlipExtensionList(new BlipExtension + { + Uri = (StringValue)"{28A0092B-C50C-407E-A947-70E740481C1C}" + })) + { + Embed = (StringValue)relationshipId, + CompressionState = (EnumValue)BlipCompressionValues.Print + }, new Stretch(new FillRectangle())); + array4[2] = new DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties(new Transform2D(new Offset + { + X = (Int64Value)0L, + Y = (Int64Value)0L + }, new Extents + { + Cx = (Int64Value)990000L, + Cy = (Int64Value)792000L + }), new PresetGeometry(new AdjustValueList()) + { + Preset = (EnumValue)ShapeTypeValues.Rectangle + }); + array3[0] = new DocumentFormat.OpenXml.Drawing.Pictures.Picture(array4); + array2[0] = new GraphicData(array3) + { + Uri = (StringValue)"http://schemas.openxmlformats.org/drawingml/2006/picture" + }; + obj[4] = new Graphic(array2); + array[0] = new Inline(obj) + { + DistanceFromTop = (UInt32Value)0u, + DistanceFromBottom = (UInt32Value)0u, + DistanceFromLeft = (UInt32Value)0u, + DistanceFromRight = (UInt32Value)0u, + EditId = (HexBinaryValue)"50D07946" + }; + + Drawing drawing = new Drawing(array); + Body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(new DocumentFormat.OpenXml.Wordprocessing.Run(drawing))); + } + + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Helpers/TableService.cs b/Lab 2/Belianin_2/MyCustomComponents/Helpers/TableService.cs new file mode 100644 index 0000000..77002df --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Helpers/TableService.cs @@ -0,0 +1,288 @@ +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml.Wordprocessing; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml; +using MyCustomComponents.Helpers; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Helpers +{ + public class TableService + { + private Document _document = null; + + private Body _body = null; + + private DocumentFormat.OpenXml.Wordprocessing.Table _table = null; + + // Свойство для создания или получения документа + private Document Document + { + get + { + if (_document == null) + { + _document = new Document(); + } + + return _document; + } + } + + // Свойство для создания или получения содержимого (Body) документа + private Body Body + { + get + { + if (_body == null) + { + _body = Document.AppendChild(new Body()); + } + + return _body; + } + } + + // Свойство для создания или получения таблицы + private DocumentFormat.OpenXml.Wordprocessing.Table Table + { + get + { + if (_table == null) + { + _table = new DocumentFormat.OpenXml.Wordprocessing.Table(); + } + + return _table; + } + } + + // Метод для сохранения документа + public void SaveDoc(string filepath) + { + if (filepath.IsEmpty()) + { + throw new ArgumentNullException("Имя файла не задано"); + } + + if (_document == null || _body == null) + { + throw new ArgumentNullException("Документ не сформирован, сохранять нечего"); + } + + if (_table != null) + { + Body.Append(Table); + } + + using WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document); + MainDocumentPart mainDocumentPart = wordprocessingDocument.AddMainDocumentPart(); + mainDocumentPart.Document = Document; + + } + + // Метод для загрузки данных в таблицу + public void LoadDataToTableWithColumnHeader(string[,] data) + { + for (int i = 0; i < data.GetLength(0); i++) + { + DocumentFormat.OpenXml.Wordprocessing.TableRow tableRow = Table.Elements().ElementAt(i); + + for (int j = 0; j < data.GetLength(1); j++) + { + DocumentFormat.OpenXml.Wordprocessing.TableCell tableCell = new DocumentFormat.OpenXml.Wordprocessing.TableCell(); + tableCell.Append(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(new DocumentFormat.OpenXml.Wordprocessing.Run(new DocumentFormat.OpenXml.Wordprocessing.Text(data[i, j])))); + tableRow.Append(tableCell); + } + } + } + + // Метод для добавления заголовка с объединением колонок + private void AddColumnHeaderCellMergeByCols(string header, int rowHeight) + { + DocumentFormat.OpenXml.Wordprocessing.TableRow tableRow = new DocumentFormat.OpenXml.Wordprocessing.TableRow(); + int? rowHeight2 = rowHeight; + + DocumentFormat.OpenXml.Wordprocessing.TableCell tableCell = CreateCell(header, null, rowHeight2); + tableCell.Append(new HorizontalMerge + { + Val = (EnumValue)MergedCellValues.Restart + }); + + tableRow.Append(tableCell); + tableCell = new DocumentFormat.OpenXml.Wordprocessing.TableCell(new DocumentFormat.OpenXml.Wordprocessing.Paragraph()); + tableCell.Append(new HorizontalMerge + { + Val = (EnumValue)MergedCellValues.Continue + }); + + tableRow.Append(tableCell); + Table.Append(tableRow); + } + + // Метод для создания ячейки таблицы + private static DocumentFormat.OpenXml.Wordprocessing.TableCell CreateCell(string header, int? columnWidth = null, int? rowHeight = null) + { + DocumentFormat.OpenXml.Wordprocessing.TableCell tableCell = new DocumentFormat.OpenXml.Wordprocessing.TableCell(); + DocumentFormat.OpenXml.Wordprocessing.TableCellProperties tableCellProperties = new DocumentFormat.OpenXml.Wordprocessing.TableCellProperties(); + + // Задание высоты строки, если указана + if (rowHeight.HasValue) + { + tableCellProperties.Append(new TableRowHeight + { + Val = (UInt32Value)Convert.ToUInt32(rowHeight) + }); + } + + // Задание ширины колонки, если указана + if (columnWidth.HasValue) + { + tableCellProperties.Append(new TableCellWidth + { + Width = (StringValue)columnWidth.Value.ToString() + }); + } + + tableCellProperties.Append(new TableCellVerticalAlignment + { + Val = (EnumValue)TableVerticalAlignmentValues.Center + }); + + tableCell.Append(tableCellProperties); + DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph(); + DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties paragraphProperties = new DocumentFormat.OpenXml.Wordprocessing.ParagraphProperties(); + + paragraphProperties.Append(new Justification + { + Val = (EnumValue)JustificationValues.Center + }); + + paragraph.Append(paragraphProperties); + + if (header.HaveText()) + { + DocumentFormat.OpenXml.Wordprocessing.Run run = new DocumentFormat.OpenXml.Wordprocessing.Run(); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties(new Bold())); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(header)); + paragraph.Append(run); + } + + tableCell.Append(paragraph); + return tableCell; + } + + // Метод для создания заголовков колонок + public void CreateColumnHeader(WordWithTableConfig config) + { + // Логика создания заголовков таблицы с объединением ячеек + int k; + for (k = 0; k < config.ColumnUnion[0].StartIndex; k++) + { + AddColumnHeaderCellMergeByCols(config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == k).Item3, config.ColumnsRowsWidth[k].Row); + } + + int j; + for (j = 0; j < config.ColumnUnion.Count; j++) + { + int l; + for (l = config.ColumnUnion[j].StartIndex; l < config.ColumnUnion[j].StartIndex + config.ColumnUnion[j].Count; l++) + { + DocumentFormat.OpenXml.Wordprocessing.TableRow tableRow = new DocumentFormat.OpenXml.Wordprocessing.TableRow(); + + if (l == config.ColumnUnion[j].StartIndex) + { + DocumentFormat.OpenXml.Wordprocessing.TableCell tableCell = CreateCell(config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == l && x.RowIndex == 0).Item3); + + tableCell.Append(new VerticalMerge + { + Val = (EnumValue)MergedCellValues.Restart + }); + + tableRow.Append(tableCell); + } + else + { + DocumentFormat.OpenXml.Wordprocessing.TableCell tableCell2 = new DocumentFormat.OpenXml.Wordprocessing.TableCell(new DocumentFormat.OpenXml.Wordprocessing.Paragraph()); + + tableCell2.Append(new VerticalMerge + { + Val = (EnumValue)MergedCellValues.Continue + }); + + tableRow.Append(tableCell2); + } + + OpenXmlElement[] array = new OpenXmlElement[1]; + string item = config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == l && x.RowIndex == 1).Item3; + int? rowHeight = config.ColumnsRowsWidth[l].Row; + + array[0] = CreateCell(item, null, rowHeight); + tableRow.Append(array); + Table.Append(tableRow); + } + + if (j >= config.ColumnUnion.Count - 1) + { + continue; + } + + for (int m = config.ColumnUnion[j].StartIndex + config.ColumnUnion[j].Count; m < config.ColumnUnion[j + 1].StartIndex; m++) + { + AddColumnHeaderCellMergeByCols(config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == j).Item3, config.ColumnsRowsWidth[j].Row); + } + } + + int i; + for (i = config.ColumnUnion[config.ColumnUnion.Count - 1].StartIndex + config.ColumnUnion[config.ColumnUnion.Count - 1].Count; i < config.ColumnsRowsWidth.Count; i++) + { + AddColumnHeaderCellMergeByCols(config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == i).Item3, config.ColumnsRowsWidth[i].Row); + } + } + + // Метод для создания таблицы с заголовком + public void CreateTableWithHeader() + { + Table.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.TableProperties(new TableBorders(new DocumentFormat.OpenXml.Wordprocessing.TopBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }, new DocumentFormat.OpenXml.Wordprocessing.BottomBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }, new DocumentFormat.OpenXml.Wordprocessing.LeftBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }, new DocumentFormat.OpenXml.Wordprocessing.RightBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }, new DocumentFormat.OpenXml.Wordprocessing.InsideHorizontalBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }, new DocumentFormat.OpenXml.Wordprocessing.InsideVerticalBorder + { + Val = new EnumValue(BorderValues.Single), + Size = (UInt32Value)12u + }))); + } + + // Метод для создания заголовка документа + public void CreateHeader(string header) + { + DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph = Body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph()); + DocumentFormat.OpenXml.Wordprocessing.Run run = paragraph.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Run()); + + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.RunProperties(new Bold())); + run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text(header)); + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/Location.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/Location.cs new file mode 100644 index 0000000..5e9180c --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/Location.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public enum Location + { + Left, + Right, + Top, + Bottom + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/WordConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/WordConfig.cs new file mode 100644 index 0000000..f065806 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/WordConfig.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public class WordConfig + { + public string FilePath { get; set; } + + public string Header { get; set; } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithDiagramConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithDiagramConfig.cs new file mode 100644 index 0000000..6302fbf --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithDiagramConfig.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public class WordWithDiagramConfig : WordConfig + { + public string ChartTitle { get; set; } + + public Location LegendLocation { get; set; } + + public Dictionary> Data { get; set; } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithImageConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithImageConfig.cs new file mode 100644 index 0000000..c646098 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithImageConfig.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public class WordWithImageConfig : WordConfig + { + public List Images { get; set; } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableConfig.cs new file mode 100644 index 0000000..c6bc3c8 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableConfig.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public class WordWithTableConfig : WordConfig + { + public bool UseUnion { get; set; } + + public (int Columns, int Rows) ColumnsRowsDataCount { get; set; } + + public List<(int Column, int Row)> ColumnsRowsWidth { get; set; } + + public List<(int StartIndex, int Count)> ColumnUnion { get; set; } + + public List<(int ColumnIndex, int RowIndex, string Header, string PropertyName)> Headers { get; set; } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableDataConfig.cs b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableDataConfig.cs new file mode 100644 index 0000000..c2826bd --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/Models/WordWithTableDataConfig.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents.Models +{ + public class WordWithTableDataConfig : WordWithTableConfig + { + public List Data { get; set; } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/MyCustomComponents.csproj b/Lab 2/Belianin_2/MyCustomComponents/MyCustomComponents.csproj new file mode 100644 index 0000000..736d42d --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/MyCustomComponents.csproj @@ -0,0 +1,16 @@ + + + + net6.0-windows + enable + true + enable + + + + + + + + + diff --git a/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.Designer.cs new file mode 100644 index 0000000..45c7c22 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.Designer.cs @@ -0,0 +1,36 @@ +namespace MyCustomComponents +{ + partial class WordWithDiagram + { + /// + /// Обязательная переменная конструктора. + /// + 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/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.cs new file mode 100644 index 0000000..74cdc10 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithDiagram.cs @@ -0,0 +1,53 @@ +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.Drawing.Wordprocessing; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml; +using MyCustomComponents.Helpers; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Wordprocessing; + +namespace MyCustomComponents +{ + public partial class WordWithDiagram : Component + { + private DiagramService creator; + + // Конструктор по умолчанию + public WordWithDiagram() + { + InitializeComponent(); + creator = new DiagramService(); + } + + // Конструктор с контейнером для компонентов + public WordWithDiagram(IContainer container) + { + container.Add(this); + + InitializeComponent(); + creator = new DiagramService(); + } + + public void CreateDoc(WordWithDiagramConfig config) + { + config.CheckFields(); + + // Создание заголовка + creator.CreateHeader(config.Header); + + // Создание диаграммы + creator.CreatePieChart(config); + + // Сохранение в файл + creator.SaveDoc(config.FilePath); + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.Designer.cs new file mode 100644 index 0000000..f647659 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.Designer.cs @@ -0,0 +1,36 @@ +namespace MyCustomComponents +{ + partial class WordWithImages + { + /// + /// Обязательная переменная конструктора. + /// + 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/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.cs new file mode 100644 index 0000000..9b34690 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithImages.cs @@ -0,0 +1,59 @@ +using DocumentFormat.OpenXml.Drawing.Wordprocessing; +using DocumentFormat.OpenXml.Drawing; +using DocumentFormat.OpenXml.Packaging; +using DocumentFormat.OpenXml; +using MyCustomComponents.Helpers; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using DocumentFormat.OpenXml.Wordprocessing; +using DocumentFormat.OpenXml.Drawing.Charts; +using DocumentFormat.OpenXml.Drawing.Diagrams; +using System.Reflection; + +namespace MyCustomComponents +{ + public partial class WordWithImages : Component + { + private ImageService creator; + + // Конструктор по умолчанию + public WordWithImages() + { + InitializeComponent(); + creator = new ImageService(); + } + + // Конструктор с контейнером для компонентов + public WordWithImages(IContainer container) + { + container.Add(this); + InitializeComponent(); + creator = new ImageService(); + } + + // Метод для создания документа Word с изображениями + public void CreateDoc(WordWithImageConfig config) + { + config.CheckFields(); + + // Создание заголовка + creator.CreateHeader(config.Header); + + // Создание и добавление всех изображений + foreach (byte[] image in config.Images) + { + creator.CreateImage(image); + } + + // Сохранение файла + creator.SaveDoc(config.FilePath); + } + } +} diff --git a/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.Designer.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.Designer.cs new file mode 100644 index 0000000..d0d7fb2 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.Designer.cs @@ -0,0 +1,36 @@ +namespace MyCustomComponents +{ + partial class WordWithTable + { + /// + /// Обязательная переменная конструктора. + /// + 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/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.cs b/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.cs new file mode 100644 index 0000000..2196225 --- /dev/null +++ b/Lab 2/Belianin_2/MyCustomComponents/WordWithTable.cs @@ -0,0 +1,71 @@ +using MyCustomComponents.Helpers; +using MyCustomComponents.Models; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MyCustomComponents +{ + public partial class WordWithTable : Component + { + private TableService creator; + + // Конструктор + public WordWithTable() + { + InitializeComponent(); + creator = new TableService(); + } + + // Конструктор с контейнером + public WordWithTable(IContainer container) + { + container.Add(this); + + InitializeComponent(); + creator = new TableService(); + } + + // Метод для создания документа с таблицей + public void CreateDoc(WordWithTableDataConfig config) + { + config.CheckFields(); + config.ColumnsRowsDataCount = (config.Data.Count + 2, config.ColumnsRowsWidth.Count); + + // Создание заголовка + creator.CreateHeader(config.Header); + + // Создание таблицы с заголовком + creator.CreateTableWithHeader(); + + // Создание заголовков столбцов + creator.CreateColumnHeader(config); + + // Создание массива данных для таблицы + string[,] array = new string[config.ColumnsRowsWidth.Count, config.Data.Count]; + for (int j = 0; j < config.Data.Count; j++) + { + int i; + + for (i = 0; i < config.ColumnsRowsWidth.Count; i++) + { + (int, int, string, string) tuple = config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == i && x.RowIndex == 1); + if (tuple.Equals(default((int, int, string, string)))) + { + tuple = config.Headers.FirstOrDefault<(int, int, string, string)>(((int ColumnIndex, int RowIndex, string Header, string PropertyName) x) => x.ColumnIndex == i && x.RowIndex == 0); + } + + array[i, j] = config.Data[j].GetType().GetProperty(tuple.Item4)!.GetValue(config.Data[j], null)!.ToString(); + } + } + + // Загрузка данных в таблицу и последующее сохранение документа + creator.LoadDataToTableWithColumnHeader(array); + creator.SaveDoc(config.FilePath); + } + } +} diff --git a/Lab 2/WordWithDiagramDocx.docx b/Lab 2/WordWithDiagramDocx.docx new file mode 100644 index 0000000..38549d9 Binary files /dev/null and b/Lab 2/WordWithDiagramDocx.docx differ diff --git a/Lab 2/WordWithImageDocx.docx b/Lab 2/WordWithImageDocx.docx new file mode 100644 index 0000000..b362b51 Binary files /dev/null and b/Lab 2/WordWithImageDocx.docx differ diff --git a/Lab 2/WordWithTableDocx.docx b/Lab 2/WordWithTableDocx.docx new file mode 100644 index 0000000..7b48acb Binary files /dev/null and b/Lab 2/WordWithTableDocx.docx differ