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){ } + } +}