diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln b/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
index 315c441..585063b 100644
--- a/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3.sln
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35122.118
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cop.Borovkov.Var3", "Cop.Borovkov.Var3\Cop.Borovkov.Var3.csproj", "{A8604186-0CDE-4504-805B-46104141269A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cop.Borovkov.Var3", "Cop.Borovkov.Var3\Cop.Borovkov.Var3.csproj", "{A8604186-0CDE-4504-805B-46104141269A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCustomComponents", "TestCustomComponents\TestCustomComponents.csproj", "{E2C46D08-ACCE-4547-922B-E92AD76D99C8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +17,10 @@ Global
{A8604186-0CDE-4504-805B-46104141269A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8604186-0CDE-4504-805B-46104141269A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8604186-0CDE-4504-805B-46104141269A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E2C46D08-ACCE-4547-922B-E92AD76D99C8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.Designer.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.Designer.cs
new file mode 100644
index 0000000..b8df7b9
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.Designer.cs
@@ -0,0 +1,63 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ partial class CustomDataTable
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ outDataGridView = new DataGridView();
+ ((System.ComponentModel.ISupportInitialize)outDataGridView).BeginInit();
+ SuspendLayout();
+ //
+ // outDataGridView
+ //
+ outDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ outDataGridView.ColumnHeadersVisible = false;
+ outDataGridView.Dock = DockStyle.Fill;
+ outDataGridView.Location = new Point(0, 0);
+ outDataGridView.Name = "outDataGridView";
+ outDataGridView.RowHeadersVisible = false;
+ outDataGridView.RowHeadersWidth = 51;
+ outDataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
+ outDataGridView.Size = new Size(849, 396);
+ outDataGridView.TabIndex = 0;
+ //
+ // CustomDataTable
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(outDataGridView);
+ Name = "CustomDataTable";
+ Size = new Size(849, 396);
+ ((System.ComponentModel.ISupportInitialize)outDataGridView).EndInit();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private DataGridView outDataGridView;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs
new file mode 100644
index 0000000..477bb22
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.cs
@@ -0,0 +1,124 @@
+using Cop.Borovkov.Var3.Models;
+
+namespace Cop.Borovkov.Var3.Components
+{
+ ///
+ /// Визуальный компонент вывода таблицы значений
+ ///
+ public partial class CustomDataTable : UserControl
+ {
+ ///
+ ///
+ public CustomDataTable()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Определить структуру таблицы
+ ///
+ ///
+ public void ConfigureColumns(params CustomDataTableColumnParameter[] columnParameters)
+ {
+ outDataGridView.Columns.Clear();
+
+ foreach (var columnParametr in columnParameters)
+ {
+ DataGridViewTextBoxColumn column = new()
+ {
+ Name = columnParametr.HeaderName,
+ HeaderText = columnParametr.HeaderName,
+ DataPropertyName = columnParametr.PropertyName,
+ Visible = columnParametr.Visible,
+ };
+
+ if (columnParametr.Width != 0)
+ {
+ column.Width = columnParametr.Width;
+ }
+ else
+ {
+ column.AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells;
+ }
+
+ outDataGridView.Columns.Add(column);
+ }
+ }
+
+ ///
+ /// Отчистить таблицу
+ ///
+ public void Clear()
+ => outDataGridView.Rows.Clear();
+
+ ///
+ /// Индекс выбранной строки
+ ///
+ public int SelectedRow
+ {
+ get => outDataGridView.CurrentRow.Index;
+
+ set
+ {
+ outDataGridView.CurrentRow.Selected = false;
+ outDataGridView.Rows[value].Selected = true;
+ }
+ }
+
+ ///
+ /// Получить стоку таблицы в виде объекта
+ ///
+ ///
+ ///
+ ///
+ public TType? GetRow(int rowIndex) where TType : new()
+ {
+ Type type = typeof(TType);
+ var element = new TType();
+
+ if (element is null)
+ {
+ return default;
+ }
+
+ var row = outDataGridView.Rows[rowIndex].Cells;
+
+ for (int i = 0; i < row.Count; i++)
+ {
+ if (string.IsNullOrEmpty(row[i].OwningColumn.DataPropertyName))
+ {
+ continue;
+ }
+
+ var field = type.GetProperty(row[i].OwningColumn.DataPropertyName);
+ field?.SetValue(element, row[i].Value);
+ }
+
+ return element;
+ }
+
+ ///
+ /// Заполнить таблицу
+ ///
+ ///
+ ///
+ public void Fill(IList insertValues)
+ {
+ Clear();
+
+ Type type = typeof(TType);
+
+ for (int i = 0; i < insertValues.Count(); ++i)
+ {
+ var row = insertValues[i];
+ outDataGridView.Rows.Add();
+
+ for (int j = 0; j < outDataGridView.ColumnCount; ++j)
+ {
+ outDataGridView.Rows[i].Cells[j].Value
+ = type.GetProperty(outDataGridView.Columns[j].DataPropertyName)?.GetValue(row)!;
+ }
+ }
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.resx b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomDataTable.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/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.Designer.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.Designer.cs
new file mode 100644
index 0000000..d11c76b
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.Designer.cs
@@ -0,0 +1,61 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ partial class CustomListBox
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ InerlistBox = new ListBox();
+ SuspendLayout();
+ //
+ // InerlistBox
+ //
+ InerlistBox.Dock = DockStyle.Fill;
+ InerlistBox.FormattingEnabled = true;
+ InerlistBox.ItemHeight = 15;
+ InerlistBox.Location = new Point(0, 0);
+ InerlistBox.Margin = new Padding(3, 2, 3, 2);
+ InerlistBox.Name = "InerlistBox";
+ InerlistBox.Size = new Size(131, 112);
+ InerlistBox.TabIndex = 0;
+ InerlistBox.SelectedIndexChanged += InerlistBox_SelectedIndexChanged;
+ //
+ // CustomListBox
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(InerlistBox);
+ Margin = new Padding(3, 2, 3, 2);
+ Name = "CustomListBox";
+ Size = new Size(131, 112);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private ListBox InerlistBox;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.cs
new file mode 100644
index 0000000..48714b4
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.cs
@@ -0,0 +1,78 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ ///
+ /// Визуальный компонент выбора из списка значений
+ ///
+ public partial class CustomListBox : UserControl
+ {
+ private event EventHandler? _selectedChanged;
+ private event Action? _errorOccured;
+
+ ///
+ ///
+ public CustomListBox()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Событие возникающие при изменении списка
+ ///
+ public event EventHandler ValueChanged
+ {
+ add => _selectedChanged += value;
+ remove => _selectedChanged -= value;
+ }
+
+ ///
+ /// Обработка ошибок
+ ///
+ public event Action AnErrorOccurred
+ {
+ add => _errorOccured += value;
+ remove => _errorOccured -= value;
+ }
+
+ ///
+ /// Заполнить список значениями
+ ///
+ /// Список значений
+ public void FillValues(IEnumerable strings)
+ {
+ InerlistBox.Items.Clear();
+ InerlistBox.Items.AddRange(strings.ToArray());
+ }
+
+ ///
+ /// Очистить список
+ ///
+ public void Clear()
+ {
+ InerlistBox.ClearSelected();
+ InerlistBox.DataSource = null;
+ InerlistBox.Items.Clear();
+ InerlistBox.Refresh();
+ }
+
+ private void InerlistBox_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ try
+ {
+ _selectedChanged?.Invoke(sender, e);
+ }
+ catch (Exception ex)
+ {
+ _errorOccured?.Invoke(ex);
+ }
+ }
+
+ ///
+ /// Выбранное значение
+ ///
+ public string Selected
+ {
+ get => (string?)InerlistBox.SelectedItem ?? string.Empty;
+ set => InerlistBox.SelectedItem = value;
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.resx b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomListBox.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/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.Designer.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.Designer.cs
new file mode 100644
index 0000000..7bfedd6
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.Designer.cs
@@ -0,0 +1,74 @@
+namespace Cop.Borovkov.Var3.Components
+{
+ partial class CustomNumericInputField
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ isNullcheckBox = new CheckBox();
+ inputField = new TextBox();
+ SuspendLayout();
+ //
+ // isNullcheckBox
+ //
+ isNullcheckBox.AutoSize = true;
+ isNullcheckBox.Location = new Point(3, 7);
+ isNullcheckBox.Margin = new Padding(3, 2, 3, 2);
+ isNullcheckBox.Name = "isNullcheckBox";
+ isNullcheckBox.Size = new Size(18, 17);
+ isNullcheckBox.TabIndex = 0;
+ isNullcheckBox.UseVisualStyleBackColor = true;
+ isNullcheckBox.CheckedChanged += IsNullcheckBox_CheckedChanged;
+ //
+ // inputField
+ //
+ inputField.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ inputField.Location = new Point(24, 2);
+ inputField.Margin = new Padding(3, 2, 3, 2);
+ inputField.Name = "inputField";
+ inputField.Size = new Size(173, 23);
+ inputField.TabIndex = 1;
+ inputField.TextChanged += InputField_TextChanged;
+ //
+ // CustomNumericInputField
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(inputField);
+ Controls.Add(isNullcheckBox);
+ Margin = new Padding(3, 2, 3, 2);
+ Name = "CustomNumericInputField";
+ Size = new Size(199, 26);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private CheckBox isNullcheckBox;
+ private TextBox inputField;
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.cs
new file mode 100644
index 0000000..c7ba971
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.cs
@@ -0,0 +1,99 @@
+using Cop.Borovkov.Var3.Exceptions;
+
+namespace Cop.Borovkov.Var3.Components
+{
+ ///
+ /// Визуальный компонент ввода целочисленного значения допускающего null
+ ///
+ public partial class CustomNumericInputField : UserControl
+ {
+ private event EventHandler? _numericInputChanged;
+
+ private event Action? _errorOccured;
+
+ ///
+ ///
+ public CustomNumericInputField()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Событие возникающие при изменении поля ввода
+ ///
+ public event EventHandler NumericInputChanged
+ {
+ add => _numericInputChanged += value;
+ remove => _numericInputChanged -= value;
+ }
+
+ ///
+ /// Обработка ошибок
+ ///
+ public event Action AnErrorOccurred
+ {
+ add => _errorOccured += value;
+ remove => _errorOccured -= value;
+ }
+
+ ///
+ /// Значения поля ввода
+ ///
+ public int? Value
+ {
+ get
+ {
+ if (isNullcheckBox.Checked)
+ {
+ return null;
+ }
+
+ if (int.TryParse(inputField.Text, out var value))
+ {
+ return value;
+ }
+
+ throw new InvalidNumericInputValueException();
+ }
+ set
+ {
+ isNullcheckBox.Checked = value is null;
+
+ if (!isNullcheckBox.Checked)
+ {
+ inputField.Text = value.ToString();
+ }
+ }
+ }
+
+ private void IsNullcheckBox_CheckedChanged(object sender, EventArgs e)
+ {
+ inputField.Enabled = !isNullcheckBox.Checked;
+ if (!inputField.Enabled)
+ {
+ inputField.Text = string.Empty;
+ }
+
+ try
+ {
+ _numericInputChanged?.Invoke(sender, e);
+ }
+ catch (Exception ex)
+ {
+ _errorOccured?.Invoke(ex);
+ }
+ }
+
+ private void InputField_TextChanged(object sender, EventArgs e)
+ {
+ try
+ {
+ _numericInputChanged?.Invoke(sender, e);
+ }
+ catch (Exception ex)
+ {
+ _errorOccured?.Invoke(ex);
+ }
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.resx b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Components/CustomNumericInputField.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/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Exceptions/InvalidNumericInputValueException.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Exceptions/InvalidNumericInputValueException.cs
new file mode 100644
index 0000000..bb2cc1d
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Exceptions/InvalidNumericInputValueException.cs
@@ -0,0 +1,9 @@
+namespace Cop.Borovkov.Var3.Exceptions
+{
+ public class InvalidNumericInputValueException : Exception
+ {
+ public InvalidNumericInputValueException() { }
+
+ public InvalidNumericInputValueException(string message) : base(message) { }
+ }
+}
diff --git a/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/CustomDataTableColumnParameter.cs b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/CustomDataTableColumnParameter.cs
new file mode 100644
index 0000000..60bc5a8
--- /dev/null
+++ b/Cop.Borovkov.Var3/Cop.Borovkov.Var3/Models/CustomDataTableColumnParameter.cs
@@ -0,0 +1,13 @@
+namespace Cop.Borovkov.Var3.Models
+{
+ public record CustomDataTableColumnParameter
+ {
+ public string HeaderName { get; init; } = string.Empty;
+
+ public int Width { get; init; } = 0;
+
+ public bool Visible { get; init; } = true;
+
+ public string PropertyName { get; init; } = string.Empty;
+ }
+}
diff --git a/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.Designer.cs b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.Designer.cs
new file mode 100644
index 0000000..f405307
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.Designer.cs
@@ -0,0 +1,246 @@
+namespace TestCustomComponents
+{
+ partial class Form1
+ {
+ ///
+ /// 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()
+ {
+ customDataTable1 = new Cop.Borovkov.Var3.Components.CustomDataTable();
+ customListBox1 = new Cop.Borovkov.Var3.Components.CustomListBox();
+ customNumericInputField1 = new Cop.Borovkov.Var3.Components.CustomNumericInputField();
+ button1 = new Button();
+ button2 = new Button();
+ button3 = new Button();
+ richTextBox1 = new RichTextBox();
+ button4 = new Button();
+ button5 = new Button();
+ button6 = new Button();
+ button7 = new Button();
+ button8 = new Button();
+ button9 = new Button();
+ button10 = new Button();
+ button11 = new Button();
+ button12 = new Button();
+ SuspendLayout();
+ //
+ // customDataTable1
+ //
+ customDataTable1.Location = new Point(297, 23);
+ customDataTable1.Name = "customDataTable1";
+ customDataTable1.Size = new Size(491, 212);
+ customDataTable1.TabIndex = 0;
+ //
+ // customListBox1
+ //
+ customListBox1.Location = new Point(12, 11);
+ customListBox1.Margin = new Padding(3, 2, 3, 2);
+ customListBox1.Name = "customListBox1";
+ customListBox1.Selected = "";
+ customListBox1.Size = new Size(164, 140);
+ customListBox1.TabIndex = 1;
+ //
+ // customNumericInputField1
+ //
+ customNumericInputField1.Location = new Point(12, 155);
+ customNumericInputField1.Margin = new Padding(3, 2, 3, 2);
+ customNumericInputField1.Name = "customNumericInputField1";
+ customNumericInputField1.Size = new Size(249, 32);
+ customNumericInputField1.TabIndex = 2;
+ //
+ // button1
+ //
+ button1.Location = new Point(26, 309);
+ button1.Name = "button1";
+ button1.Size = new Size(94, 29);
+ button1.TabIndex = 3;
+ button1.Text = "button1";
+ button1.UseVisualStyleBackColor = true;
+ button1.Click += button1_Click;
+ //
+ // button2
+ //
+ button2.Location = new Point(126, 309);
+ button2.Name = "button2";
+ button2.Size = new Size(94, 29);
+ button2.TabIndex = 4;
+ button2.Text = "button2";
+ button2.UseVisualStyleBackColor = true;
+ button2.Click += button2_Click;
+ //
+ // button3
+ //
+ button3.Location = new Point(226, 309);
+ button3.Name = "button3";
+ button3.Size = new Size(94, 29);
+ button3.TabIndex = 5;
+ button3.Text = "button3";
+ button3.UseVisualStyleBackColor = true;
+ button3.Click += button3_Click;
+ //
+ // richTextBox1
+ //
+ richTextBox1.Location = new Point(567, 241);
+ richTextBox1.Name = "richTextBox1";
+ richTextBox1.Size = new Size(125, 165);
+ richTextBox1.TabIndex = 6;
+ richTextBox1.Text = "";
+ //
+ // button4
+ //
+ button4.Location = new Point(698, 241);
+ button4.Name = "button4";
+ button4.Size = new Size(94, 29);
+ button4.TabIndex = 7;
+ button4.Text = "button4";
+ button4.UseVisualStyleBackColor = true;
+ button4.Click += button4_Click;
+ //
+ // button5
+ //
+ button5.Location = new Point(26, 344);
+ button5.Name = "button5";
+ button5.Size = new Size(94, 29);
+ button5.TabIndex = 8;
+ button5.Text = "button5";
+ button5.UseVisualStyleBackColor = true;
+ button5.Click += button5_Click;
+ //
+ // button6
+ //
+ button6.Location = new Point(126, 344);
+ button6.Name = "button6";
+ button6.Size = new Size(94, 29);
+ button6.TabIndex = 9;
+ button6.Text = "button6";
+ button6.UseVisualStyleBackColor = true;
+ button6.Click += button6_Click;
+ //
+ // button7
+ //
+ button7.Location = new Point(226, 344);
+ button7.Name = "button7";
+ button7.Size = new Size(94, 29);
+ button7.TabIndex = 10;
+ button7.Text = "button7";
+ button7.UseVisualStyleBackColor = true;
+ button7.Click += button7_Click;
+ //
+ // button8
+ //
+ button8.Location = new Point(26, 379);
+ button8.Name = "button8";
+ button8.Size = new Size(94, 29);
+ button8.TabIndex = 11;
+ button8.Text = "button8";
+ button8.UseVisualStyleBackColor = true;
+ button8.Click += button8_Click;
+ //
+ // button9
+ //
+ button9.Location = new Point(126, 377);
+ button9.Name = "button9";
+ button9.Size = new Size(94, 29);
+ button9.TabIndex = 12;
+ button9.Text = "button9";
+ button9.UseVisualStyleBackColor = true;
+ button9.Click += button9_Click;
+ //
+ // button10
+ //
+ button10.Location = new Point(226, 377);
+ button10.Name = "button10";
+ button10.Size = new Size(94, 29);
+ button10.TabIndex = 13;
+ button10.Text = "button10";
+ button10.UseVisualStyleBackColor = true;
+ button10.Click += button10_Click;
+ //
+ // button11
+ //
+ button11.Location = new Point(26, 414);
+ button11.Name = "button11";
+ button11.Size = new Size(94, 29);
+ button11.TabIndex = 14;
+ button11.Text = "button11";
+ button11.UseVisualStyleBackColor = true;
+ button11.Click += button11_Click;
+ //
+ // button12
+ //
+ button12.Location = new Point(126, 414);
+ button12.Name = "button12";
+ button12.Size = new Size(94, 29);
+ button12.TabIndex = 15;
+ button12.Text = "button12";
+ button12.UseVisualStyleBackColor = true;
+ button12.Click += button12_Click;
+ //
+ // Form1
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(800, 450);
+ Controls.Add(button12);
+ Controls.Add(button11);
+ Controls.Add(button10);
+ Controls.Add(button9);
+ Controls.Add(button8);
+ Controls.Add(button7);
+ Controls.Add(button6);
+ Controls.Add(button5);
+ Controls.Add(button4);
+ Controls.Add(richTextBox1);
+ Controls.Add(button3);
+ Controls.Add(button2);
+ Controls.Add(button1);
+ Controls.Add(customNumericInputField1);
+ Controls.Add(customListBox1);
+ Controls.Add(customDataTable1);
+ Name = "Form1";
+ Text = "Form1";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Cop.Borovkov.Var3.Components.CustomDataTable customDataTable1;
+ private Cop.Borovkov.Var3.Components.CustomListBox customListBox1;
+ private Cop.Borovkov.Var3.Components.CustomNumericInputField customNumericInputField1;
+ private Button button1;
+ private Button button2;
+ private Button button3;
+ private RichTextBox richTextBox1;
+ private Button button4;
+ private Button button5;
+ private Button button6;
+ private Button button7;
+ private Button button8;
+ private Button button9;
+ private Button button10;
+ private Button button11;
+ private Button button12;
+ }
+}
diff --git a/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.cs b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.cs
new file mode 100644
index 0000000..ec95158
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.cs
@@ -0,0 +1,122 @@
+using TestCustomComponents.Models;
+
+namespace TestCustomComponents
+{
+ public partial class Form1 : Form
+ {
+ public Form1()
+ {
+ InitializeComponent();
+ }
+
+ private void Log(string message)
+ {
+ richTextBox1.Text = $"{richTextBox1.Text}\n{message}";
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ customListBox1.AnErrorOccurred += ex => Log(ex.Message);
+ customListBox1.ValueChanged += (obj, sender) => Log($"Selected1 is {customListBox1.Selected}");
+ customNumericInputField1.AnErrorOccurred += ex => Log(ex.Message);
+ customNumericInputField1.NumericInputChanged += (obj, sender) => Log("Test 4 ok");
+
+ customListBox1.FillValues(["hello", "world", "123", "321"]);
+
+ customListBox1.Selected = "123";
+ }
+
+ private void button2_Click(object sender, EventArgs e)
+ {
+ customListBox1.Clear();
+ customListBox1.Selected = "234";
+ }
+
+ private void button3_Click(object sender, EventArgs e)
+ {
+ Log($"Selected2 is {customNumericInputField1.Value?.ToString() ?? "null"}");
+ }
+
+ private void button4_Click(object sender, EventArgs e)
+ {
+ richTextBox1.Clear();
+ }
+
+ private void button5_Click(object sender, EventArgs e)
+ {
+ customNumericInputField1.Value = 3333;
+ }
+
+ private void button6_Click(object sender, EventArgs e)
+ {
+ customNumericInputField1.Value = null;
+ }
+
+ private void button7_Click(object sender, EventArgs e)
+ {
+ customDataTable1.ConfigureColumns(
+ new()
+ {
+ HeaderName = "Id",
+ PropertyName = nameof(TestModel.Id),
+ Visible = false,
+ },
+ new()
+ {
+ HeaderName = "Name",
+ PropertyName = nameof(TestModel.Name),
+ Width = 100,
+ },
+ new()
+ {
+ HeaderName = "Age",
+ PropertyName = nameof(TestModel.Age),
+ }
+ );
+ }
+
+ private void button8_Click(object sender, EventArgs e)
+ {
+ customDataTable1.Fill([
+ new(){
+ Id = 1,
+ Name = "Vasya",
+ Age = 5,
+ },
+ new()
+ {
+ Id = 2,
+ Name = "Vilthare",
+ Age = 3,
+ },
+ new()
+ {
+ Id = 3,
+ Name = "MOMO",
+ Age = 10,
+ },
+ ]);
+ }
+
+ private void button9_Click(object sender, EventArgs e)
+ {
+ customDataTable1.Clear();
+ }
+
+ private void button10_Click(object sender, EventArgs e)
+ {
+ Log($"selected3 {customDataTable1.SelectedRow}");
+ }
+
+ private void button11_Click(object sender, EventArgs e)
+ {
+ customDataTable1.SelectedRow = customNumericInputField1.Value!.Value;
+ }
+
+ private void button12_Click(object sender, EventArgs e)
+ {
+ var elem = customDataTable1.GetRow(customDataTable1.SelectedRow)!;
+ Log($"Selected: id={elem.Id} name={elem.Name} age={elem.Age}");
+ }
+ }
+}
diff --git a/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.resx b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/Forms/Form1.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/Cop.Borovkov.Var3/TestCustomComponents/Models/TestModel.cs b/Cop.Borovkov.Var3/TestCustomComponents/Models/TestModel.cs
new file mode 100644
index 0000000..053c6d2
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/Models/TestModel.cs
@@ -0,0 +1,11 @@
+namespace TestCustomComponents.Models
+{
+ public class TestModel
+ {
+ public int Id { get; set; }
+
+ public string Name { get; set; }
+
+ public int Age { get; set; }
+ }
+}
diff --git a/Cop.Borovkov.Var3/TestCustomComponents/Program.cs b/Cop.Borovkov.Var3/TestCustomComponents/Program.cs
new file mode 100644
index 0000000..bf2c653
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/Program.cs
@@ -0,0 +1,17 @@
+namespace TestCustomComponents
+{
+ 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 Form1());
+ }
+ }
+}
\ No newline at end of file
diff --git a/Cop.Borovkov.Var3/TestCustomComponents/TestCustomComponents.csproj b/Cop.Borovkov.Var3/TestCustomComponents/TestCustomComponents.csproj
new file mode 100644
index 0000000..588393f
--- /dev/null
+++ b/Cop.Borovkov.Var3/TestCustomComponents/TestCustomComponents.csproj
@@ -0,0 +1,15 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
\ No newline at end of file