diff --git a/Lab 1/Belianin_1/Belianin_1.sln b/Lab 1/Belianin_1/Belianin_1.sln
new file mode 100644
index 0000000..b133bd4
--- /dev/null
+++ b/Lab 1/Belianin_1/Belianin_1.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 1/Belianin_1/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj
new file mode 100644
index 0000000..9c31612
--- /dev/null
+++ b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/DesktopWithMyVisualComponents.csproj
@@ -0,0 +1,15 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Lab 1/Belianin_1/DesktopWithMyVisualComponents/Device.cs b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/Device.cs
new file mode 100644
index 0000000..0c3a0eb
--- /dev/null
+++ b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/Device.cs
@@ -0,0 +1,28 @@
+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 Device(string serialNumber, string deviceType, string model)
+ {
+ SerialNumber = serialNumber;
+ Model = model;
+ DeviceType = deviceType;
+ }
+
+ public Device() { }
+ }
+}
diff --git a/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.Designer.cs b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.Designer.cs
new file mode 100644
index 0000000..78a0294
--- /dev/null
+++ b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.Designer.cs
@@ -0,0 +1,380 @@
+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()
+ {
+ customInputRangeNumber = new MyCustomComponents.CustomInputRangeNumber();
+ buttonCheck = new Button();
+ labelCheckValue = new Label();
+ textBoxMin = new TextBox();
+ textBoxMax = new TextBox();
+ buttonSetBorders = new Button();
+ labelMin = new Label();
+ labelMax = new Label();
+ labelRange = new Label();
+ groupBoxInput = new GroupBox();
+ groupBoxSelected = new GroupBox();
+ buttonGetSelected = new Button();
+ labelSelectedValue = new Label();
+ buttonClear = new Button();
+ buttonAdd = new Button();
+ textBoxAdd = new TextBox();
+ customSelectedCheckedListBoxProperty = new MyCustomComponents.CustomSelectedCheckedListBoxProperty();
+ groupBoxData = new GroupBox();
+ labelDeviceType = new Label();
+ labelModel = new Label();
+ labelSerialNum = new Label();
+ buttonGetFromTree = new Button();
+ buttonAddToTree = new Button();
+ comboBoxDeviceType = new ComboBox();
+ textBoxModel = new TextBox();
+ textBoxSerialNumber = new TextBox();
+ customTreeView = new MyCustomComponents.CustomTreeView();
+ groupBoxInput.SuspendLayout();
+ groupBoxSelected.SuspendLayout();
+ groupBoxData.SuspendLayout();
+ SuspendLayout();
+ //
+ // customInputRangeNumber
+ //
+ customInputRangeNumber.AutoValidate = AutoValidate.Disable;
+ customInputRangeNumber.CausesValidation = false;
+ customInputRangeNumber.Location = new Point(30, 19);
+ customInputRangeNumber.Margin = new Padding(3, 2, 3, 2);
+ customInputRangeNumber.MaxValue = new decimal(new int[] { -1, -1, -1, 0 });
+ customInputRangeNumber.MinValue = new decimal(new int[] { -1, -1, -1, int.MinValue });
+ customInputRangeNumber.Name = "customInputRangeNumber";
+ customInputRangeNumber.Size = new Size(134, 30);
+ customInputRangeNumber.TabIndex = 0;
+ customInputRangeNumber.Value = new decimal(new int[] { 0, 0, 0, 0 });
+ //
+ // buttonCheck
+ //
+ buttonCheck.Location = new Point(171, 22);
+ buttonCheck.Name = "buttonCheck";
+ buttonCheck.Size = new Size(126, 23);
+ buttonCheck.TabIndex = 1;
+ buttonCheck.Text = "Check";
+ buttonCheck.UseVisualStyleBackColor = true;
+ buttonCheck.Click += buttonCheck_Click;
+ //
+ // labelCheckValue
+ //
+ labelCheckValue.AutoSize = true;
+ labelCheckValue.Location = new Point(30, 111);
+ labelCheckValue.Name = "labelCheckValue";
+ labelCheckValue.Size = new Size(65, 15);
+ labelCheckValue.TabIndex = 2;
+ labelCheckValue.Text = "Enter value";
+ //
+ // textBoxMin
+ //
+ textBoxMin.Location = new Point(30, 71);
+ textBoxMin.Name = "textBoxMin";
+ textBoxMin.Size = new Size(55, 23);
+ textBoxMin.TabIndex = 3;
+ textBoxMin.KeyPress += textBoxMin_KeyPress;
+ //
+ // textBoxMax
+ //
+ textBoxMax.Location = new Point(103, 71);
+ textBoxMax.Name = "textBoxMax";
+ textBoxMax.Size = new Size(53, 23);
+ textBoxMax.TabIndex = 4;
+ textBoxMax.KeyPress += textBoxMax_KeyPress;
+ //
+ // buttonSetBorders
+ //
+ buttonSetBorders.Location = new Point(171, 71);
+ buttonSetBorders.Name = "buttonSetBorders";
+ buttonSetBorders.Size = new Size(126, 23);
+ buttonSetBorders.TabIndex = 5;
+ buttonSetBorders.Text = "Set Borders";
+ buttonSetBorders.UseVisualStyleBackColor = true;
+ buttonSetBorders.Click += buttonSetBorders_Click;
+ //
+ // labelMin
+ //
+ labelMin.AutoSize = true;
+ labelMin.Location = new Point(29, 54);
+ labelMin.Name = "labelMin";
+ labelMin.Size = new Size(56, 15);
+ labelMin.TabIndex = 6;
+ labelMin.Text = "MinValue";
+ //
+ // labelMax
+ //
+ labelMax.AutoSize = true;
+ labelMax.Location = new Point(101, 54);
+ labelMax.Name = "labelMax";
+ labelMax.Size = new Size(58, 15);
+ labelMax.TabIndex = 7;
+ labelMax.Text = "MaxValue";
+ //
+ // labelRange
+ //
+ labelRange.AutoSize = true;
+ labelRange.Location = new Point(88, 75);
+ labelRange.Name = "labelRange";
+ labelRange.Size = new Size(12, 15);
+ labelRange.TabIndex = 8;
+ labelRange.Text = "-";
+ //
+ // groupBoxInput
+ //
+ groupBoxInput.Controls.Add(customInputRangeNumber);
+ groupBoxInput.Controls.Add(labelCheckValue);
+ groupBoxInput.Controls.Add(labelRange);
+ groupBoxInput.Controls.Add(buttonCheck);
+ groupBoxInput.Controls.Add(labelMax);
+ groupBoxInput.Controls.Add(textBoxMin);
+ groupBoxInput.Controls.Add(labelMin);
+ groupBoxInput.Controls.Add(textBoxMax);
+ groupBoxInput.Controls.Add(buttonSetBorders);
+ groupBoxInput.Location = new Point(12, 252);
+ groupBoxInput.Name = "groupBoxInput";
+ groupBoxInput.Size = new Size(311, 190);
+ groupBoxInput.TabIndex = 9;
+ groupBoxInput.TabStop = false;
+ groupBoxInput.Text = "Input";
+ //
+ // groupBoxSelected
+ //
+ groupBoxSelected.Controls.Add(buttonGetSelected);
+ groupBoxSelected.Controls.Add(labelSelectedValue);
+ groupBoxSelected.Controls.Add(buttonClear);
+ groupBoxSelected.Controls.Add(buttonAdd);
+ groupBoxSelected.Controls.Add(textBoxAdd);
+ groupBoxSelected.Controls.Add(customSelectedCheckedListBoxProperty);
+ groupBoxSelected.Location = new Point(340, 253);
+ groupBoxSelected.Name = "groupBoxSelected";
+ groupBoxSelected.Size = new Size(311, 190);
+ groupBoxSelected.TabIndex = 10;
+ groupBoxSelected.TabStop = false;
+ groupBoxSelected.Text = "Selected";
+ //
+ // buttonGetSelected
+ //
+ buttonGetSelected.Location = new Point(192, 144);
+ buttonGetSelected.Name = "buttonGetSelected";
+ buttonGetSelected.Size = new Size(100, 23);
+ buttonGetSelected.TabIndex = 14;
+ buttonGetSelected.Text = "Get Selected";
+ buttonGetSelected.UseVisualStyleBackColor = true;
+ buttonGetSelected.Click += buttonGetSelected_Click;
+ //
+ // labelSelectedValue
+ //
+ labelSelectedValue.AutoSize = true;
+ labelSelectedValue.Location = new Point(192, 111);
+ labelSelectedValue.Name = "labelSelectedValue";
+ labelSelectedValue.Size = new Size(82, 15);
+ labelSelectedValue.TabIndex = 11;
+ labelSelectedValue.Text = "Selected value";
+ //
+ // buttonClear
+ //
+ buttonClear.Location = new Point(192, 81);
+ buttonClear.Name = "buttonClear";
+ buttonClear.Size = new Size(100, 23);
+ buttonClear.TabIndex = 13;
+ buttonClear.Text = "Clear";
+ buttonClear.UseVisualStyleBackColor = true;
+ buttonClear.Click += buttonClear_Click;
+ //
+ // buttonAdd
+ //
+ buttonAdd.Location = new Point(192, 52);
+ buttonAdd.Name = "buttonAdd";
+ buttonAdd.Size = new Size(100, 23);
+ buttonAdd.TabIndex = 12;
+ buttonAdd.Text = "Add or Select";
+ buttonAdd.UseVisualStyleBackColor = true;
+ buttonAdd.Click += buttonAdd_Click;
+ //
+ // textBoxAdd
+ //
+ textBoxAdd.Location = new Point(192, 23);
+ textBoxAdd.Name = "textBoxAdd";
+ textBoxAdd.Size = new Size(100, 23);
+ textBoxAdd.TabIndex = 11;
+ //
+ // customSelectedCheckedListBoxProperty
+ //
+ customSelectedCheckedListBoxProperty.Location = new Point(36, 19);
+ customSelectedCheckedListBoxProperty.Margin = new Padding(3, 2, 3, 2);
+ customSelectedCheckedListBoxProperty.Name = "customSelectedCheckedListBoxProperty";
+ customSelectedCheckedListBoxProperty.SelectedElement = "";
+ customSelectedCheckedListBoxProperty.Size = new Size(150, 157);
+ customSelectedCheckedListBoxProperty.TabIndex = 0;
+ //
+ // groupBoxData
+ //
+ groupBoxData.Controls.Add(labelDeviceType);
+ groupBoxData.Controls.Add(labelModel);
+ groupBoxData.Controls.Add(labelSerialNum);
+ groupBoxData.Controls.Add(buttonGetFromTree);
+ groupBoxData.Controls.Add(buttonAddToTree);
+ groupBoxData.Controls.Add(comboBoxDeviceType);
+ groupBoxData.Controls.Add(textBoxModel);
+ groupBoxData.Controls.Add(textBoxSerialNumber);
+ groupBoxData.Controls.Add(customTreeView);
+ groupBoxData.Location = new Point(12, 12);
+ groupBoxData.Name = "groupBoxData";
+ groupBoxData.Size = new Size(639, 230);
+ groupBoxData.TabIndex = 11;
+ groupBoxData.TabStop = false;
+ groupBoxData.Text = "Data";
+ //
+ // labelDeviceType
+ //
+ labelDeviceType.AutoSize = true;
+ labelDeviceType.Location = new Point(432, 116);
+ labelDeviceType.Name = "labelDeviceType";
+ labelDeviceType.Size = new Size(91, 15);
+ labelDeviceType.TabIndex = 8;
+ labelDeviceType.Text = "Тип устройства";
+ //
+ // labelModel
+ //
+ labelModel.AutoSize = true;
+ labelModel.Location = new Point(432, 72);
+ labelModel.Name = "labelModel";
+ labelModel.Size = new Size(50, 15);
+ labelModel.TabIndex = 7;
+ labelModel.Text = "Модель";
+ //
+ // labelSerialNum
+ //
+ labelSerialNum.AutoSize = true;
+ labelSerialNum.Location = new Point(432, 28);
+ labelSerialNum.Name = "labelSerialNum";
+ labelSerialNum.Size = new Size(105, 15);
+ labelSerialNum.TabIndex = 6;
+ labelSerialNum.Text = "Серия устройства";
+ //
+ // buttonGetFromTree
+ //
+ buttonGetFromTree.Location = new Point(432, 195);
+ buttonGetFromTree.Name = "buttonGetFromTree";
+ buttonGetFromTree.Size = new Size(188, 23);
+ buttonGetFromTree.TabIndex = 5;
+ buttonGetFromTree.Text = "Get Selected";
+ buttonGetFromTree.UseVisualStyleBackColor = true;
+ buttonGetFromTree.Click += buttonGetFromTree_Click;
+ //
+ // buttonAddToTree
+ //
+ buttonAddToTree.Location = new Point(432, 166);
+ buttonAddToTree.Name = "buttonAddToTree";
+ buttonAddToTree.Size = new Size(188, 23);
+ buttonAddToTree.TabIndex = 4;
+ buttonAddToTree.Text = "Add";
+ buttonAddToTree.UseVisualStyleBackColor = true;
+ buttonAddToTree.Click += buttonAddToTree_Click;
+ //
+ // comboBoxDeviceType
+ //
+ comboBoxDeviceType.FormattingEnabled = true;
+ comboBoxDeviceType.Location = new Point(432, 134);
+ comboBoxDeviceType.Name = "comboBoxDeviceType";
+ comboBoxDeviceType.Size = new Size(188, 23);
+ comboBoxDeviceType.TabIndex = 3;
+ //
+ // textBoxModel
+ //
+ textBoxModel.Location = new Point(432, 90);
+ textBoxModel.Name = "textBoxModel";
+ textBoxModel.Size = new Size(188, 23);
+ textBoxModel.TabIndex = 2;
+ //
+ // textBoxSerialNumber
+ //
+ textBoxSerialNumber.Location = new Point(432, 46);
+ textBoxSerialNumber.Name = "textBoxSerialNumber";
+ textBoxSerialNumber.Size = new Size(188, 23);
+ textBoxSerialNumber.TabIndex = 1;
+ //
+ // customTreeView
+ //
+ customTreeView.Location = new Point(15, 22);
+ customTreeView.Margin = new Padding(3, 2, 3, 2);
+ customTreeView.Name = "customTreeView";
+ customTreeView.Size = new Size(398, 202);
+ customTreeView.TabIndex = 0;
+ //
+ // FormMain
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(667, 450);
+ Controls.Add(groupBoxData);
+ Controls.Add(groupBoxSelected);
+ Controls.Add(groupBoxInput);
+ Name = "FormMain";
+ Text = "FormMain";
+ groupBoxInput.ResumeLayout(false);
+ groupBoxInput.PerformLayout();
+ groupBoxSelected.ResumeLayout(false);
+ groupBoxSelected.PerformLayout();
+ groupBoxData.ResumeLayout(false);
+ groupBoxData.PerformLayout();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private MyCustomComponents.CustomInputRangeNumber customInputRangeNumber;
+ private Button buttonCheck;
+ private Label labelCheckValue;
+ private TextBox textBoxMin;
+ private TextBox textBoxMax;
+ private Button buttonSetBorders;
+ private Label labelMin;
+ private Label labelMax;
+ private Label labelRange;
+ 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 labelSerialNum;
+ }
+}
\ No newline at end of file
diff --git a/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.cs b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.cs
new file mode 100644
index 0000000..6df1bc8
--- /dev/null
+++ b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.cs
@@ -0,0 +1,186 @@
+using MyCustomComponents;
+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" },
+ new Device { Id = 2, SerialNumber = "SM-G3412", DeviceType = "Мобильный телефон", Model = "Samsung Galaxy S24" },
+ new Device { Id = 3, SerialNumber = "CO2UD8471", DeviceType = "Ноутбук", Model = "MacBook Pro" },
+ new Device { Id = 4, SerialNumber = "R80NZD8812", DeviceType = "Умные часы", Model = "Galaxy Watch 4" },
+ new Device { Id = 5, SerialNumber = "FN738214", DeviceType = "Умные часы", Model = "Apple Watch 3", },
+ };
+
+ 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();
+
+ // Присоединить обработчик события при изменении значения
+ 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;
+ }
+ }
+}
diff --git a/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.resx b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/FormMain.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 1/Belianin_1/DesktopWithMyVisualComponents/Program.cs b/Lab 1/Belianin_1/DesktopWithMyVisualComponents/Program.cs
new file mode 100644
index 0000000..7aba605
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Attributes/AlwaysCreateAttribute .cs b/Lab 1/Belianin_1/MyCustomComponents/Attributes/AlwaysCreateAttribute .cs
new file mode 100644
index 0000000..db0392f
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.Designer.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.Designer.cs
new file mode 100644
index 0000000..afbf042
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.cs
new file mode 100644
index 0000000..e3da2f6
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.resx b/Lab 1/Belianin_1/MyCustomComponents/CustomInputRangeNumber.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.Designer.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.Designer.cs
new file mode 100644
index 0000000..ca537d7
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.cs
new file mode 100644
index 0000000..43999dd
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.resx b/Lab 1/Belianin_1/MyCustomComponents/CustomSelectedCheckedListBoxProperty.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomTreeView.Designer.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomTreeView.Designer.cs
new file mode 100644
index 0000000..35784f9
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/CustomTreeView.cs b/Lab 1/Belianin_1/MyCustomComponents/CustomTreeView.cs
new file mode 100644
index 0000000..e670360
--- /dev/null
+++ b/Lab 1/Belianin_1/MyCustomComponents/CustomTreeView.cs
@@ -0,0 +1,175 @@
+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");
+ }
+
+ // Ищем индекс свойства в иерархии
+ int index = hierarchy.IndexOf(propertyName);
+ if (index == -1)
+ {
+ throw new PropertyNullException("Property not found in hierarchy");
+ }
+
+ // Получаем первый узел в дереве, либо нулл, если узлов нет
+ TreeNode currentNode = treeView.SelectedNode;
+
+ // Проходимся по иерархии
+ 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 1/Belianin_1/MyCustomComponents/CustomTreeView.resx b/Lab 1/Belianin_1/MyCustomComponents/CustomTreeView.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Extensions/HierarchyNullException.cs b/Lab 1/Belianin_1/MyCustomComponents/Extensions/HierarchyNullException.cs
new file mode 100644
index 0000000..1699429
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Extensions/InvalidSelectedElementException.cs b/Lab 1/Belianin_1/MyCustomComponents/Extensions/InvalidSelectedElementException.cs
new file mode 100644
index 0000000..f5b0986
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Extensions/PropertyNullException.cs b/Lab 1/Belianin_1/MyCustomComponents/Extensions/PropertyNullException.cs
new file mode 100644
index 0000000..0de8cea
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Extensions/RangeException.cs b/Lab 1/Belianin_1/MyCustomComponents/Extensions/RangeException.cs
new file mode 100644
index 0000000..aa8e00c
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/Extensions/ValueOutOfRangeException .cs b/Lab 1/Belianin_1/MyCustomComponents/Extensions/ValueOutOfRangeException .cs
new file mode 100644
index 0000000..91e3b33
--- /dev/null
+++ b/Lab 1/Belianin_1/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 1/Belianin_1/MyCustomComponents/MyCustomComponents.csproj b/Lab 1/Belianin_1/MyCustomComponents/MyCustomComponents.csproj
new file mode 100644
index 0000000..060aa1c
--- /dev/null
+++ b/Lab 1/Belianin_1/MyCustomComponents/MyCustomComponents.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net6.0-windows
+ enable
+ true
+ enable
+
+
+