diff --git a/Components/Components.csproj b/Components/Components.csproj
new file mode 100644
index 0000000..d501559
--- /dev/null
+++ b/Components/Components.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
diff --git a/Components/Exceptions/UncheckedNullException.cs b/Components/Exceptions/UncheckedNullException.cs
new file mode 100644
index 0000000..e66fdae
--- /dev/null
+++ b/Components/Exceptions/UncheckedNullException.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Components.Exceptions
+{
+ public class UncheckedNullException : Exception
+ {
+ public UncheckedNullException() { }
+ public UncheckedNullException(string message) : base(message) { }
+ }
+}
diff --git a/Components/Exceptions/UnexpectedTypeException.cs b/Components/Exceptions/UnexpectedTypeException.cs
new file mode 100644
index 0000000..e742c0a
--- /dev/null
+++ b/Components/Exceptions/UnexpectedTypeException.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Components.Exceptions
+{
+ public class UnexpectedTypeException : Exception
+ {
+ public UnexpectedTypeException() { }
+ public UnexpectedTypeException(string message) : base(message) { }
+ }
+}
diff --git a/Components/Visual/ColumnInfo.cs b/Components/Visual/ColumnInfo.cs
new file mode 100644
index 0000000..08a8955
--- /dev/null
+++ b/Components/Visual/ColumnInfo.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Components.Visual
+{
+ public class ColumnInfo
+ {
+ public string HeaderText { get; set; } = string.Empty;
+ public int Width { get; set; }
+ public bool Visible { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string DataPropertyName { get; set; } = string.Empty;
+ }
+}
diff --git a/Components/Visual/UserControlIntegerInput.Designer.cs b/Components/Visual/UserControlIntegerInput.Designer.cs
new file mode 100644
index 0000000..5a4661d
--- /dev/null
+++ b/Components/Visual/UserControlIntegerInput.Designer.cs
@@ -0,0 +1,71 @@
+namespace Components
+{
+ partial class UserControlIntegerInput
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ textBoxInteger = new TextBox();
+ checkBoxNullable = new CheckBox();
+ SuspendLayout();
+ //
+ // textBoxInteger
+ //
+ textBoxInteger.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ textBoxInteger.Location = new Point(24, 1);
+ textBoxInteger.Name = "textBoxInteger";
+ textBoxInteger.Size = new Size(144, 23);
+ textBoxInteger.TabIndex = 0;
+ textBoxInteger.TextChanged += textBoxInteger_TextChanged;
+ //
+ // checkBoxNullable
+ //
+ checkBoxNullable.AutoSize = true;
+ checkBoxNullable.Location = new Point(3, 5);
+ checkBoxNullable.Name = "checkBoxNullable";
+ checkBoxNullable.Size = new Size(15, 14);
+ checkBoxNullable.TabIndex = 1;
+ checkBoxNullable.UseVisualStyleBackColor = true;
+ checkBoxNullable.CheckedChanged += checkBoxNullable_CheckedChanged;
+ //
+ // UserControlIntegerInput
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(checkBoxNullable);
+ Controls.Add(textBoxInteger);
+ Name = "UserControlIntegerInput";
+ Size = new Size(171, 30);
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private TextBox textBoxInteger;
+ private CheckBox checkBoxNullable;
+ }
+}
diff --git a/Components/Visual/UserControlIntegerInput.cs b/Components/Visual/UserControlIntegerInput.cs
new file mode 100644
index 0000000..b6f982c
--- /dev/null
+++ b/Components/Visual/UserControlIntegerInput.cs
@@ -0,0 +1,71 @@
+using Components.Exceptions;
+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 Components
+{
+ public partial class UserControlIntegerInput : UserControl
+ {
+ private event EventHandler? _elementChanged;
+ private event Action? _errorOccured;
+ public string Error { get; private set; }
+ public int? InputtedInteger
+ {
+ get
+ {
+ if (checkBoxNullable.Checked)
+ {
+ return null;
+ }
+ if (textBoxInteger.Text.Equals(string.Empty) || textBoxInteger.Text == null)
+ {
+ throw new UncheckedNullException("Input was null, but checkbox wasnt checked");
+ }
+ if (Int32.TryParse(textBoxInteger.Text, out var number))
+ {
+ return number;
+ }
+ throw new UnexpectedTypeException("Input was non integer");
+ }
+ set
+ {
+ textBoxInteger.Text = value.ToString();
+ checkBoxNullable.Checked = value == null;
+ }
+ }
+ public event EventHandler ElementChanged
+ {
+ add { _elementChanged += value; }
+ remove { _elementChanged -= value; }
+ }
+ public event Action AnErrorOccurred
+ {
+ add { _errorOccured += value; }
+ remove { _errorOccured -= value; }
+ }
+ public UserControlIntegerInput()
+ {
+ InitializeComponent();
+ Error = string.Empty;
+ }
+
+ private void textBoxInteger_TextChanged(object sender, EventArgs e)
+ {
+ _elementChanged?.Invoke(this, e);
+ }
+
+ private void checkBoxNullable_CheckedChanged(object sender, EventArgs e)
+ {
+ textBoxInteger.Enabled = !checkBoxNullable.Checked;
+ textBoxInteger.Text = null;
+ _elementChanged?.Invoke(this, e);
+ }
+ }
+}
diff --git a/Components/Visual/UserControlIntegerInput.resx b/Components/Visual/UserControlIntegerInput.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Components/Visual/UserControlIntegerInput.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/Components/Visual/UserControlStringsListBox.Designer.cs b/Components/Visual/UserControlStringsListBox.Designer.cs
new file mode 100644
index 0000000..382b913
--- /dev/null
+++ b/Components/Visual/UserControlStringsListBox.Designer.cs
@@ -0,0 +1,58 @@
+namespace Components
+{
+ partial class UserControlStringsListBox
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ listBoxStrings = new ListBox();
+ SuspendLayout();
+ //
+ // listBoxStrings
+ //
+ listBoxStrings.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ listBoxStrings.FormattingEnabled = true;
+ listBoxStrings.ItemHeight = 15;
+ listBoxStrings.Location = new Point(3, 3);
+ listBoxStrings.Name = "listBoxStrings";
+ listBoxStrings.Size = new Size(144, 139);
+ listBoxStrings.TabIndex = 0;
+ listBoxStrings.SelectedValueChanged += listBoxStrings_SelectedValueChanged;
+ //
+ // UserControlStringsListBox
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(listBoxStrings);
+ Name = "UserControlStringsListBox";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private ListBox listBoxStrings;
+ }
+}
diff --git a/Components/Visual/UserControlStringsListBox.cs b/Components/Visual/UserControlStringsListBox.cs
new file mode 100644
index 0000000..8693f27
--- /dev/null
+++ b/Components/Visual/UserControlStringsListBox.cs
@@ -0,0 +1,70 @@
+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 Components
+{
+ public partial class UserControlStringsListBox : UserControl
+ {
+ private event EventHandler? _listChanged;
+ private event Action? _errorOccured;
+ public string Error { get; private set; }
+ public string ListElement
+ {
+ get
+ {
+ return listBoxStrings.SelectedItem?.ToString();
+ }
+ set
+ {
+ if (listBoxStrings.Items.Contains(value))
+ {
+ listBoxStrings.SelectedItem = value;
+ }
+ }
+ }
+ public event EventHandler ListChanged
+ {
+ add { _listChanged += value; }
+ remove { _listChanged -= value; }
+ }
+ public event Action AnErrorOccurred
+ {
+ add { _errorOccured += value; }
+ remove { _errorOccured -= value; }
+ }
+ public UserControlStringsListBox()
+ {
+ InitializeComponent();
+ Error = string.Empty;
+ }
+
+ public void AddList(List l)
+ {
+ try
+ {
+ listBoxStrings.Items.AddRange(l.ToArray());
+ }
+ catch (Exception ex)
+ {
+ Error = ex.Message;
+ _errorOccured?.Invoke();
+ }
+ }
+ public void ClearList()
+ {
+ listBoxStrings.Items.Clear();
+ }
+
+ private void listBoxStrings_SelectedValueChanged(object sender, EventArgs e)
+ {
+ _listChanged?.Invoke(sender, e);
+ }
+ }
+}
diff --git a/Components/Visual/UserControlStringsListBox.resx b/Components/Visual/UserControlStringsListBox.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Components/Visual/UserControlStringsListBox.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/Components/Visual/UserControlTable.Designer.cs b/Components/Visual/UserControlTable.Designer.cs
new file mode 100644
index 0000000..01b9469
--- /dev/null
+++ b/Components/Visual/UserControlTable.Designer.cs
@@ -0,0 +1,62 @@
+namespace Components
+{
+ partial class UserControlTable
+ {
+ ///
+ /// Обязательная переменная конструктора.
+ ///
+ 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()
+ {
+ dataGridViewTable = new DataGridView();
+ ((System.ComponentModel.ISupportInitialize)dataGridViewTable).BeginInit();
+ SuspendLayout();
+ //
+ // dataGridViewTable
+ //
+ dataGridViewTable.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ dataGridViewTable.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ dataGridViewTable.Location = new Point(3, 3);
+ dataGridViewTable.Name = "dataGridViewTable";
+ dataGridViewTable.RowHeadersVisible = false;
+ dataGridViewTable.RowTemplate.Height = 25;
+ dataGridViewTable.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
+ dataGridViewTable.Size = new Size(325, 150);
+ dataGridViewTable.TabIndex = 0;
+ //
+ // UserControlTable
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ Controls.Add(dataGridViewTable);
+ Name = "UserControlTable";
+ Size = new Size(331, 157);
+ ((System.ComponentModel.ISupportInitialize)dataGridViewTable).EndInit();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private DataGridView dataGridViewTable;
+ }
+}
diff --git a/Components/Visual/UserControlTable.cs b/Components/Visual/UserControlTable.cs
new file mode 100644
index 0000000..116c37f
--- /dev/null
+++ b/Components/Visual/UserControlTable.cs
@@ -0,0 +1,97 @@
+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 Components.Visual;
+
+namespace Components
+{
+ public partial class UserControlTable : UserControl
+ {
+ public int index
+ {
+ get => dataGridViewTable.SelectedRows.Count > 0 ? dataGridViewTable.SelectedRows[0].Index : -1;
+ set
+ {
+ if (value >= 0 && value < dataGridViewTable.Rows.Count)
+ {
+ dataGridViewTable.ClearSelection();
+ dataGridViewTable.Rows[value].Selected = true;
+ }
+ }
+ }
+ public UserControlTable()
+ {
+ InitializeComponent();
+ }
+
+ public void ConfigureColumns(List columnInfo)
+ {
+ dataGridViewTable.Columns.Clear();
+ for (int i = 0; i < columnInfo.Count; i++)
+ {
+ DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn
+ {
+ Name = columnInfo[i].Name,
+ HeaderText = columnInfo[i].HeaderText,
+ Width = columnInfo[i].Width,
+ Visible = columnInfo[i].Visible,
+ DataPropertyName = columnInfo[i].DataPropertyName,
+ };
+ dataGridViewTable.Columns.Add(column);
+ }
+ }
+
+ public void ClearRows()
+ {
+ dataGridViewTable.Rows.Clear();
+ }
+
+ public void AddList(List values)
+ {
+ ClearRows();
+ var props = typeof(T).GetProperties();
+
+ foreach (T value in values)
+ {
+ int newRowInd = dataGridViewTable.Rows.Add();
+ foreach (DataGridViewColumn col in dataGridViewTable.Columns)
+ {
+ var prop = props.FirstOrDefault(x => x.Name == col.DataPropertyName)
+ ?? throw new InvalidOperationException($"No property {col.DataPropertyName} found in type {typeof(T).Name}");
+ var val = prop.GetValue(value);
+ dataGridViewTable.Rows[newRowInd].Cells[col.Index].Value = val;
+ }
+ }
+ }
+
+ public T GetObjectFromRow()
+ where T : new()
+ {
+ if (dataGridViewTable.SelectedRows.Count == 0)
+ {
+ throw new InvalidOperationException("At least one row must be selected");
+ }
+
+ T returnObject = new();
+
+ var selectedRow = dataGridViewTable.SelectedRows[0];
+ var props = typeof(T).GetProperties();
+ var cells = dataGridViewTable.Rows[selectedRow.Index].Cells;
+
+ for (int i = 0; i < dataGridViewTable.ColumnCount; i++)
+ {
+ var curCell = cells[i];
+ var prop = props.FirstOrDefault(x => x.Name == dataGridViewTable.Columns[i].DataPropertyName);
+ prop?.SetValue(returnObject, curCell.Value);
+ }
+ return returnObject;
+ }
+ }
+}
diff --git a/Components/Visual/UserControlTable.resx b/Components/Visual/UserControlTable.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Components/Visual/UserControlTable.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/ComponentsProgramming.sln b/ComponentsProgramming.sln
new file mode 100644
index 0000000..b8d9e2a
--- /dev/null
+++ b/ComponentsProgramming.sln
@@ -0,0 +1,25 @@
+
+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}") = "Components", "Components\Components.csproj", "{260D3E8C-3599-49F1-BF42-64A92DD0FB62}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {260D3E8C-3599-49F1-BF42-64A92DD0FB62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {260D3E8C-3599-49F1-BF42-64A92DD0FB62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {260D3E8C-3599-49F1-BF42-64A92DD0FB62}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {260D3E8C-3599-49F1-BF42-64A92DD0FB62}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {1208CC7E-AF27-4982-8E30-0DC89F09BBA6}
+ EndGlobalSection
+EndGlobal