diff --git a/CustomCheckedListBox.Designer.cs b/CustomCheckedListBox.Designer.cs
new file mode 100644
index 0000000..145a7dc
--- /dev/null
+++ b/CustomCheckedListBox.Designer.cs
@@ -0,0 +1,57 @@
+namespace CustomsComponentsVar2
+{
+ partial class CustomCheckedListBox
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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.Dock = DockStyle.Fill;
+ checkedListBox.FormattingEnabled = true;
+ checkedListBox.Location = new Point(0, 0);
+ checkedListBox.Name = "checkedListBox";
+ checkedListBox.Size = new Size(262, 446);
+ checkedListBox.TabIndex = 0;
+ //
+ // CustomCheckedListBox
+ //
+ AutoScaleDimensions = new SizeF(8F, 19F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(checkedListBox);
+ Name = "CustomCheckedListBox";
+ Size = new Size(262, 446);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private CheckedListBox checkedListBox;
+ }
+}
diff --git a/CustomCheckedListBox.cs b/CustomCheckedListBox.cs
new file mode 100644
index 0000000..64e8b10
--- /dev/null
+++ b/CustomCheckedListBox.cs
@@ -0,0 +1,69 @@
+namespace CustomsComponentsVar2;
+
+public partial class CustomCheckedListBox : UserControl
+{
+ private event EventHandler? _selectedChanged;
+ public CustomCheckedListBox()
+ {
+ InitializeComponent();
+ }
+
+ public string SelectedElement
+ {
+ get
+ {
+ if (checkedListBox.Items.Count == 0 || checkedListBox.Items == null)
+ {
+ return String.Empty;
+ }
+ return checkedListBox.Items.ToString();
+ }
+ set
+ {
+ if (checkedListBox.Items.Contains(value))
+ {
+ checkedListBox.SelectedItem = value;
+ }
+ }
+ }
+
+ ///
+ /// Добавить элементы
+ ///
+ ///
+ public void addElements(List s)
+ {
+ checkedListBox.Items.Clear();
+ checkedListBox.Items.AddRange(s.ToArray());
+ }
+
+ ///
+ /// Выбран элемент
+ ///
+ ///
+ ///
+ private void onItemCheck(object sender, ItemCheckEventArgs e)
+ {
+ _selectedChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ ///
+ /// Изменение индекса выбранного элемента
+ ///
+ ///
+ ///
+ private void checkedListBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (checkedListBox.CheckedItems.Count > 1)
+ {
+ foreach (int index in checkedListBox.CheckedIndices)
+ {
+ if (index != checkedListBox.SelectedIndex)
+ {
+ checkedListBox.SetItemChecked(index, false);
+ }
+ }
+ }
+ _selectedChanged?.Invoke(sender, e);
+ }
+}
diff --git a/CustomCheckedListBox.resx b/CustomCheckedListBox.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/CustomCheckedListBox.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/CustomComponentsVar2.csproj b/CustomComponentsVar2.csproj
new file mode 100644
index 0000000..3e210aa
--- /dev/null
+++ b/CustomComponentsVar2.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0-windows
+ enable
+ true
+ enable
+
+
+
diff --git a/CustomDateTimePicker.Designer.cs b/CustomDateTimePicker.Designer.cs
new file mode 100644
index 0000000..ee5a74e
--- /dev/null
+++ b/CustomDateTimePicker.Designer.cs
@@ -0,0 +1,68 @@
+namespace CustomsComponentsVar2
+{
+ partial class CustomDateTimePicker
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ dateTimePicker = new DateTimePicker();
+ label1 = new Label();
+ SuspendLayout();
+ //
+ // dateTimePicker
+ //
+ dateTimePicker.Location = new Point(121, 8);
+ dateTimePicker.Name = "dateTimePicker";
+ dateTimePicker.Size = new Size(235, 26);
+ dateTimePicker.TabIndex = 0;
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Location = new Point(7, 11);
+ label1.Name = "label1";
+ label1.Size = new Size(106, 19);
+ label1.TabIndex = 1;
+ label1.Text = "Выберите дату:";
+ //
+ // CustomDateTimePicker
+ //
+ AutoScaleDimensions = new SizeF(8F, 19F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(label1);
+ Controls.Add(dateTimePicker);
+ Name = "CustomDateTimePicker";
+ Size = new Size(365, 42);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private DateTimePicker dateTimePicker;
+ private Label label1;
+ }
+}
diff --git a/CustomDateTimePicker.cs b/CustomDateTimePicker.cs
new file mode 100644
index 0000000..ad640ab
--- /dev/null
+++ b/CustomDateTimePicker.cs
@@ -0,0 +1,39 @@
+namespace CustomsComponentsVar2;
+
+public partial class CustomDateTimePicker : UserControl
+{
+ public CustomDateTimePicker()
+ {
+ InitializeComponent();
+ }
+ public event EventHandler _dateChanged;
+ public DateTime dateStart;
+ public DateTime dateEnd;
+ public DateTime date
+ {
+ get
+ {
+ if (dateStart == null || dateEnd == null)
+ {
+ throw new RangeNotSetException("Не задан диапазон.");
+ }
+ if (date < dateStart && date > dateEnd)
+ {
+ throw new ValueNotInRangeException("Значение не входит в диапазон");
+ }
+ return date;
+ }
+ set
+ {
+ if (value >= dateStart && value <= dateEnd)
+ {
+ date = value;
+ }
+ }
+ }
+
+ public void dateChanged(DateTime date)
+ {
+ _dateChanged?.Invoke(this, date);
+ }
+}
diff --git a/CustomDateTimePicker.resx b/CustomDateTimePicker.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/CustomDateTimePicker.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/CustomTreeView.Designer.cs b/CustomTreeView.Designer.cs
new file mode 100644
index 0000000..5898334
--- /dev/null
+++ b/CustomTreeView.Designer.cs
@@ -0,0 +1,58 @@
+using System.Windows.Forms;
+
+namespace CustomsComponentsVar2
+{
+ 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.Dock = DockStyle.Fill;
+ treeView.Location = new Point(0, 0);
+ treeView.Name = "treeView";
+ treeView.Size = new Size(328, 360);
+ treeView.TabIndex = 0;
+ //
+ // CustomTreeView
+ //
+ AutoScaleDimensions = new SizeF(8F, 19F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(treeView);
+ Name = "CustomTreeView";
+ Size = new Size(328, 360);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private TreeView treeView;
+ }
+}
diff --git a/CustomTreeView.cs b/CustomTreeView.cs
new file mode 100644
index 0000000..938e86d
--- /dev/null
+++ b/CustomTreeView.cs
@@ -0,0 +1,140 @@
+namespace CustomsComponentsVar2;
+
+public partial class CustomTreeView: UserControl
+{
+ ///
+ /// Иерархия дерева по полям класса
+ ///
+ private List hierarchy;
+ ///
+ /// Список полей, для которых обязательно создаем новыую ветку (например, ФИО, на случай полных однофамильцев)
+ ///
+ private Dictionary newBranch;
+ public int SelectedIndex
+ {
+ get
+ {
+ return SelectedIndex;
+ }
+ set
+ {
+ SelectedIndex = value;
+ }
+ }
+ public CustomTreeView()
+ {
+ InitializeComponent();
+ hierarchy = new List();
+ }
+
+ ///
+ /// Устанавливает иерархию по полям класса, начиная с главного
+ ///
+ ///
+ ///
+ public void setHierarchy(List hierarchy, Dictionary newBranch)
+ {
+ this.hierarchy = hierarchy;
+ this.newBranch = newBranch;
+ }
+
+ ///
+ /// Строит дерево на основе полученных элементов
+ ///
+ ///
+ ///
+ public void build(List elements)
+ {
+ foreach (var el in elements)
+ {
+ add(el, hierarchy, treeView.Nodes, 0);
+ }
+ }
+
+ ///
+ /// Рекурсивно добавляет узлы в дерево
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void add(T el, List hierarchy, TreeNodeCollection nodes, int level)
+ {
+ // если превышено количество уровней в иерархии
+ if (level >= hierarchy.Count)
+ {
+ return;
+ }
+
+ // находим свойство (на основе иерархии) – извлекаем значение
+ string property = hierarchy[level];
+ string propertyValue = el.GetType().GetProperty(property)?.GetValue(el)?.ToString() ?? string.Empty;
+
+ // ищем, есть ли уже узел с таким названием
+ TreeNode foundNode = null;
+ foreach (TreeNode node in nodes)
+ {
+ if (node.Text == propertyValue)
+ {
+ foundNode = node;
+ break;
+ }
+ }
+
+ // если не найден ИЛИ указано, что нужно создать новый узел, то добавляем новый узел
+ if (foundNode == null || newBranch.ContainsKey(property) && newBranch[property])
+ {
+ foundNode = nodes.Add(propertyValue);
+ }
+
+ // шаг на уровень глубже
+ add(el, hierarchy, foundNode.Nodes, level + 1);
+ }
+
+ ///
+ /// получение выбранного элемента по индексу (с рефлексией)
+ ///
+ ///
+ ///
+ public T getSelected() where T : new()
+ {
+ if (SelectedIndex >= 0 && SelectedIndex < treeView.Nodes.Count)
+ {
+ TreeNode node = treeView.Nodes[SelectedIndex];
+ // если последний уровень
+ if (node.Level == hierarchy.Count)
+ {
+ T el = new T();
+ setProperties(el, node, node.Level);
+ return el;
+ }
+ }
+ return default(T);
+ }
+
+ ///
+ /// получение значений свойств элемента по узлам
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void setProperties(T el, TreeNode node, int level)
+ {
+ if (hierarchy.Count >= level)
+ {
+ var property = hierarchy[level];
+ var propertyValue = typeof(T).GetProperty(property);
+ if (propertyValue != null)
+ {
+ propertyValue.SetValue(el, node.Text);
+ }
+ }
+
+ if (node.Parent != null)
+ {
+ setProperties(el, node.Parent, level - 1);
+ }
+ }
+}
diff --git a/CustomTreeView.resx b/CustomTreeView.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/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/CustomsComponentsVar2.sln b/CustomsComponentsVar2.sln
new file mode 100644
index 0000000..ffb518e
--- /dev/null
+++ b/CustomsComponentsVar2.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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomComponentsVar2", "CustomComponentsVar2.csproj", "{02BF1C07-1A86-40B3-84AF-EA9344B5382E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsApp", "..\WinFormsApp\WinFormsApp.csproj", "{EA6E87EE-31C6-4D6F-9A1A-DAC6F3F05E45}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {02BF1C07-1A86-40B3-84AF-EA9344B5382E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {02BF1C07-1A86-40B3-84AF-EA9344B5382E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {02BF1C07-1A86-40B3-84AF-EA9344B5382E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {02BF1C07-1A86-40B3-84AF-EA9344B5382E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EA6E87EE-31C6-4D6F-9A1A-DAC6F3F05E45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EA6E87EE-31C6-4D6F-9A1A-DAC6F3F05E45}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EA6E87EE-31C6-4D6F-9A1A-DAC6F3F05E45}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EA6E87EE-31C6-4D6F-9A1A-DAC6F3F05E45}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {371DADAB-9A54-4924-95A5-295AF029F39E}
+ EndGlobalSection
+EndGlobal
diff --git a/Exception/RangeNotSetException.cs b/Exception/RangeNotSetException.cs
new file mode 100644
index 0000000..b1ae080
--- /dev/null
+++ b/Exception/RangeNotSetException.cs
@@ -0,0 +1,9 @@
+namespace CustomsComponentsVar2
+{
+ public class RangeNotSetException : System.Exception
+ {
+ public RangeNotSetException() { }
+
+ public RangeNotSetException(string message) : base(message){ }
+ }
+}
diff --git a/Exception/ValueNotInRangeException.cs b/Exception/ValueNotInRangeException.cs
new file mode 100644
index 0000000..3333cd9
--- /dev/null
+++ b/Exception/ValueNotInRangeException.cs
@@ -0,0 +1,8 @@
+namespace CustomsComponentsVar2
+{
+ public class ValueNotInRangeException : System.Exception
+ {
+ public ValueNotInRangeException() { }
+ public ValueNotInRangeException(string message) : base(message){ }
+ }
+}