ComplexDoroninLibrary 1.0.0
dotnet add package ComplexDoroninLibrary --version 1.0.0
NuGet\Install-Package ComplexDoroninLibrary -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ComplexDoroninLibrary" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ComplexDoroninLibrary" Version="1.0.0" />
<PackageReference Include="ComplexDoroninLibrary" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ComplexDoroninLibrary --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: ComplexDoroninLibrary, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ComplexDoroninLibrary@1.0.0
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ComplexDoroninLibrary&version=1.0.0
#tool nuget:?package=ComplexDoroninLibrary&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Исходный код проекта
Каждый файл выделен отдельным заголовком, код оформлен в блоках C#.
📄 MessageHelper.cs
using System.Windows.Forms;
namespace ToysStore
{
public static class MessageHelper
{
public static void Error(string text)
{
MessageBox.Show(
text,
"Ошибка",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
public static void Warning(string text)
{
MessageBox.Show(
text,
"Предупреждение",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
public static void Info(string text)
{
MessageBox.Show(
text,
"Информация",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
public static bool Confirm(string text)
{
return MessageBox.Show(
text,
"Подтверждение действия",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes;
}
}
}
📄 Models.cs
namespace ToysStore
{
public enum UserRole
{
Guest = 0,
Admin = 1,
Manager = 2,
Client = 3
}
public class CurrentUser
{
public int Id { get; set; }
public string Login { get; set; }
public string FullName { get; set; }
public UserRole Role { get; set; }
public CurrentUser()
{
FullName = "Гость";
Role = UserRole.Guest;
}
public string RoleName
{
get
{
if (Role == UserRole.Admin) return "Администратор";
if (Role == UserRole.Manager) return "Менеджер";
if (Role == UserRole.Client) return "Клиент";
return "Неавторизованный пользователь";
}
}
}
public class Product
{
public string ArticleNumber { get; set; }
public string ProductName { get; set; }
public int Unit { get; set; }
public double Price { get; set; }
public int Supplier { get; set; }
public int Manufacturer { get; set; }
public int ProductCategory { get; set; }
public double CurrentDiscount { get; set; }
public double QuantityInStock { get; set; }
public string ProductDescription { get; set; }
public string Photo { get; set; }
public string UnitName { get; set; }
public string SupplierName { get; set; }
public string ManufacturerName { get; set; }
public string CategoryName { get; set; }
public string DisplayText
{
get
{
return ArticleNumber + " | " + CategoryName + " | " + ProductName + " | " + Price.ToString("N2") + " руб.";
}
}
public override string ToString()
{
return ArticleNumber + " | " + ProductName;
}
}
public class LookupItem
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
public class OrderView
{
public int OrderNumber { get; set; }
public string OrderDate { get; set; }
public string DeliveryDate { get; set; }
public int StatusId { get; set; }
public string StatusName { get; set; }
public int PersonId { get; set; }
public int PickupPointId { get; set; }
public string PersonName { get; set; }
public string PickupAddress { get; set; }
public int PickupCode { get; set; }
public int ItemCount { get; set; }
public double Total { get; set; }
public string ProductsText { get; set; }
public double DiscountPercent { get; set; }
}
public class OrderItemView
{
public string ProductArticleNumber { get; set; }
public string ProductName { get; set; }
public double Quantity { get; set; }
public double Price { get; set; }
public double Discount { get; set; }
public double Total
{
get
{
return Quantity * Price * (1 - Discount / 100.0);
}
}
}
}
📄 DB.cs
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace ToysStore
{
public class Db
{
public const string ConnectionString =
@"Data Source=dorinmaxxx\SQLEXPRESS;Initial Catalog=demoNeHack;Integrated Security=True;Encrypt=False";
private SqlConnection Open()
{
SqlConnection con = new SqlConnection(ConnectionString);
con.Open();
return con;
}
private bool ColumnExists(string table, string column)
{
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand("SELECT COL_LENGTH(@table, @column)", con))
{
cmd.Parameters.AddWithValue("@table", "dbo." + table);
cmd.Parameters.AddWithValue("@column", column);
return cmd.ExecuteScalar() != DBNull.Value;
}
}
// Заказы больше не используют Clients: связь идет через Orders.Person -> Persons.Id.
private string GetOrderPersonColumn()
{
return "Person";
}
public CurrentUser Login(string login, string password)
{
string sql = @"
SELECT TOP 1 ua.Id, ua.Login, ua.EmployeeRole,
p.LastName + ' ' + p.FirstName + ' ' + p.MiddleName AS FullName
FROM UserAccounts ua
JOIN Persons p ON p.Id = ua.Person
WHERE ua.Login = @login AND ua.Password = @password";
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("@login", login);
cmd.Parameters.AddWithValue("@password", password);
using (SqlDataReader r = cmd.ExecuteReader())
{
if (!r.Read()) return null;
return new CurrentUser
{
Id = Convert.ToInt32(r["Id"]),
Login = r["Login"].ToString(),
FullName = r["FullName"].ToString(),
Role = (UserRole)Convert.ToInt32(r["EmployeeRole"])
};
}
}
}
public List<Product> GetProducts()
{
List<Product> list = new List<Product>();
string sql = @"
SELECT p.*, u.Name AS UnitName, s.Name AS SupplierName,
m.Name AS ManufacturerName, c.Name AS CategoryName
FROM Products p
JOIN Units u ON u.Id = p.Unit
JOIN Suppliers s ON s.Id = p.Supplier
JOIN Manufacturers m ON m.Id = p.Manufacturer
JOIN Categories c ON c.Id = p.ProductCategory
ORDER BY p.ProductName";
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
using (SqlDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
Product p = new Product();
p.ArticleNumber = r["ArticleNumber"].ToString();
p.ProductName = r["ProductName"].ToString();
p.Unit = Convert.ToInt32(r["Unit"]);
p.Price = r["Price"] == DBNull.Value ? 0 : Convert.ToDouble(r["Price"]);
p.Supplier = Convert.ToInt32(r["Supplier"]);
p.Manufacturer = Convert.ToInt32(r["Manufacturer"]);
p.ProductCategory = Convert.ToInt32(r["ProductCategory"]);
p.CurrentDiscount = r["CurrentDiscount"] == DBNull.Value ? 0 : Convert.ToDouble(r["CurrentDiscount"]);
p.QuantityInStock = r["QuantityInStock"] == DBNull.Value ? 0 : Convert.ToDouble(r["QuantityInStock"]);
p.ProductDescription = r["ProductDescription"].ToString();
p.Photo = r["Photo"] == DBNull.Value ? "" : r["Photo"].ToString();
p.UnitName = r["UnitName"].ToString();
p.SupplierName = r["SupplierName"].ToString();
p.ManufacturerName = r["ManufacturerName"].ToString();
p.CategoryName = r["CategoryName"].ToString();
list.Add(p);
}
}
return list;
}
// Таблица выбирается из белого списка, так как имя таблицы нельзя передать SQL-параметром.
public List<LookupItem> GetLookup(string table)
{
if (table != "Units" &&
table != "Suppliers" &&
table != "Manufacturers" &&
table != "Categories" &&
table != "Persons" &&
table != "PickupPoints" &&
table != "OrderStatuses")
{
throw new ArgumentException("Запрошен неизвестный справочник: " + table);
}
string nameField = "Name";
string sourceTable = table;
if (table == "Persons")
{
sourceTable = "Persons";
nameField = "LastName + ' ' + FirstName + ' ' + MiddleName";
}
if (table == "PickupPoints")
nameField = "CAST([Index] AS nvarchar) + ', ' + Address";
string sql = "SELECT Id, " + nameField + " AS Name FROM " + sourceTable + " ORDER BY Name";
List<LookupItem> list = new List<LookupItem>();
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
using (SqlDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
list.Add(new LookupItem
{
Id = Convert.ToInt32(r["Id"]),
Name = r["Name"].ToString()
});
}
}
return list;
}
public void AddProduct(Product p)
{
string sql = @"
INSERT INTO Products
(ArticleNumber, ProductName, Unit, Price, Supplier, Manufacturer, ProductCategory,
CurrentDiscount, QuantityInStock, ProductDescription, Photo)
VALUES
(@ArticleNumber, @ProductName, @Unit, @Price, @Supplier, @Manufacturer, @ProductCategory,
@CurrentDiscount, @QuantityInStock, @ProductDescription, @Photo)";
SaveProductSql(sql, p);
}
public void UpdateProduct(Product p)
{
string sql = @"
UPDATE Products SET
ProductName = @ProductName,
Unit = @Unit,
Price = @Price,
Supplier = @Supplier,
Manufacturer = @Manufacturer,
ProductCategory = @ProductCategory,
CurrentDiscount = @CurrentDiscount,
QuantityInStock = @QuantityInStock,
ProductDescription = @ProductDescription,
Photo = @Photo
WHERE ArticleNumber = @ArticleNumber";
SaveProductSql(sql, p);
}
private void SaveProductSql(string sql, Product p)
{
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("@ArticleNumber", p.ArticleNumber);
cmd.Parameters.AddWithValue("@ProductName", p.ProductName);
cmd.Parameters.AddWithValue("@Unit", p.Unit);
cmd.Parameters.AddWithValue("@Price", p.Price);
cmd.Parameters.AddWithValue("@Supplier", p.Supplier);
cmd.Parameters.AddWithValue("@Manufacturer", p.Manufacturer);
cmd.Parameters.AddWithValue("@ProductCategory", p.ProductCategory);
cmd.Parameters.AddWithValue("@CurrentDiscount", p.CurrentDiscount);
cmd.Parameters.AddWithValue("@QuantityInStock", p.QuantityInStock);
cmd.Parameters.AddWithValue("@ProductDescription", p.ProductDescription);
cmd.Parameters.AddWithValue("@Photo", string.IsNullOrWhiteSpace(p.Photo) ? (object)DBNull.Value : p.Photo);
cmd.ExecuteNonQuery();
}
}
public void DeleteProduct(string article)
{
if (IsProductUsedInOrders(article))
throw new InvalidOperationException("Товар присутствует в заказе и не может быть удален.");
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand("DELETE FROM Products WHERE ArticleNumber=@a", con))
{
cmd.Parameters.AddWithValue("@a", article);
cmd.ExecuteNonQuery();
}
}
public bool IsProductUsedInOrders(string article)
{
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM OrderItems WHERE ProductArticleNumber = @a", con))
{
cmd.Parameters.AddWithValue("@a", article);
return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
}
}
public List<OrderView> GetOrders()
{
List<OrderView> list = new List<OrderView>();
string personColumn = GetOrderPersonColumn();
string sql = @"
SELECT
o.OrderNumber,
CONVERT(nvarchar, o.OrderDate, 104) AS OrderDate,
CONVERT(nvarchar, o.DeliveryDate, 104) AS DeliveryDate,
ISNULL(o.StatusId, 2) AS StatusId,
ISNULL(os.Name, N'Новый') AS StatusName,
o." + personColumn + @" AS PersonId,
o.PickupPointAddress AS PickupPointId,
c.LastName + ' ' + c.FirstName + ' ' + c.MiddleName AS PersonName,
pp.Address AS PickupAddress,
ISNULL(o.PickupCode, 0) AS PickupCode,
COUNT(oi.ProductArticleNumber) AS ItemCount,
ISNULL(SUM(oi.Quantity * p.Price), 0) AS TotalWithoutDiscount,
ISNULL(SUM(oi.Quantity * p.Price * (1 - ISNULL(p.CurrentDiscount, 0) / 100.0)), 0) AS TotalWithDiscount,
ISNULL(
STUFF((
SELECT '; ' + p2.ProductName + ' (' + CAST(CAST(oi2.Quantity AS int) AS nvarchar) + ' шт.)'
FROM OrderItems oi2
JOIN Products p2 ON p2.ArticleNumber = oi2.ProductArticleNumber
WHERE oi2.OrderNumber = o.OrderNumber
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 2, ''),
'') AS ProductsText
FROM Orders o
LEFT JOIN OrderStatuses os ON os.Id = o.StatusId
JOIN Persons c ON c.Id = o." + personColumn + @"
JOIN PickupPoints pp ON pp.Id = o.PickupPointAddress
LEFT JOIN OrderItems oi ON oi.OrderNumber = o.OrderNumber
LEFT JOIN Products p ON p.ArticleNumber = oi.ProductArticleNumber
GROUP BY
o.OrderNumber,
o.OrderDate,
o.DeliveryDate,
o.StatusId,
os.Name,
o." + personColumn + @",
o.PickupPointAddress,
c.LastName,
c.FirstName,
c.MiddleName,
pp.Address,
o.PickupCode
ORDER BY o.OrderNumber";
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
using (SqlDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
double totalWithoutDiscount = Convert.ToDouble(r["TotalWithoutDiscount"]);
double totalWithDiscount = Convert.ToDouble(r["TotalWithDiscount"]);
double discountPercent = 0;
if (totalWithoutDiscount > 0)
discountPercent = 100 - totalWithDiscount / totalWithoutDiscount * 100;
list.Add(new OrderView
{
OrderNumber = Convert.ToInt32(r["OrderNumber"]),
OrderDate = r["OrderDate"].ToString(),
DeliveryDate = r["DeliveryDate"].ToString(),
StatusId = Convert.ToInt32(r["StatusId"]),
StatusName = r["StatusName"].ToString(),
PersonId = Convert.ToInt32(r["PersonId"]),
PickupPointId = Convert.ToInt32(r["PickupPointId"]),
PersonName = r["PersonName"].ToString(),
PickupAddress = r["PickupAddress"].ToString(),
PickupCode = Convert.ToInt32(r["PickupCode"]),
ItemCount = Convert.ToInt32(r["ItemCount"]),
Total = totalWithDiscount,
ProductsText = r["ProductsText"].ToString(),
DiscountPercent = discountPercent
});
}
}
return list;
}
public int GetNextOrderNumber()
{
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand("SELECT ISNULL(MAX(OrderNumber), 0) + 1 FROM Orders", con))
{
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
public List<OrderItemView> GetOrderItems(int orderNumber)
{
List<OrderItemView> list = new List<OrderItemView>();
string sql = @"
SELECT oi.ProductArticleNumber,
p.ProductName,
oi.Quantity,
p.Price,
ISNULL(p.CurrentDiscount, 0) AS Discount
FROM OrderItems oi
JOIN Products p ON p.ArticleNumber = oi.ProductArticleNumber
WHERE oi.OrderNumber = @OrderNumber";
using (SqlConnection con = Open())
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
using (SqlDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
list.Add(new OrderItemView
{
ProductArticleNumber = r["ProductArticleNumber"].ToString(),
ProductName = r["ProductName"].ToString(),
Quantity = Convert.ToDouble(r["Quantity"]),
Price = Convert.ToDouble(r["Price"]),
Discount = Convert.ToDouble(r["Discount"])
});
}
}
}
return list;
}
// Заказ и его состав сохраняются одной транзакцией, чтобы не получить заказ без товаров.
public void AddOrder(
int orderNumber,
DateTime orderDate,
DateTime deliveryDate,
int statusId,
int pickupPointId,
int personId,
int pickupCode,
List<OrderItemView> items)
{
using (SqlConnection con = Open())
using (SqlTransaction transaction = con.BeginTransaction())
{
try
{
string personColumn = GetOrderPersonColumn();
string orderSql = @"
INSERT INTO Orders
(OrderNumber, OrderDate, DeliveryDate, StatusId, PickupPointAddress, " + personColumn + @", PickupCode)
VALUES
(@OrderNumber, @OrderDate, @DeliveryDate, @StatusId, @PickupPointAddress, @PersonId, @PickupCode)";
using (SqlCommand cmd = new SqlCommand(orderSql, con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.Parameters.AddWithValue("@OrderDate", orderDate);
cmd.Parameters.AddWithValue("@DeliveryDate", deliveryDate);
cmd.Parameters.AddWithValue("@StatusId", statusId);
cmd.Parameters.AddWithValue("@PickupPointAddress", pickupPointId);
cmd.Parameters.AddWithValue("@PersonId", personId);
cmd.Parameters.AddWithValue("@PickupCode", pickupCode);
cmd.ExecuteNonQuery();
}
foreach (OrderItemView item in items)
{
string itemSql = @"
INSERT INTO OrderItems
(OrderNumber, ProductArticleNumber, Quantity)
VALUES
(@OrderNumber, @ProductArticleNumber, @Quantity)";
using (SqlCommand cmd = new SqlCommand(itemSql, con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.Parameters.AddWithValue("@ProductArticleNumber", item.ProductArticleNumber);
cmd.Parameters.AddWithValue("@Quantity", item.Quantity);
cmd.ExecuteNonQuery();
}
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
// При редактировании состав заказа пересоздается целиком внутри транзакции.
public void UpdateOrder(
int orderNumber,
DateTime orderDate,
DateTime deliveryDate,
int statusId,
int pickupPointId,
int personId,
int pickupCode,
List<OrderItemView> items)
{
using (SqlConnection con = Open())
using (SqlTransaction transaction = con.BeginTransaction())
{
try
{
string personColumn = GetOrderPersonColumn();
string orderSql = @"
UPDATE Orders SET
OrderDate = @OrderDate,
DeliveryDate = @DeliveryDate,
StatusId = @StatusId,
PickupPointAddress = @PickupPointAddress,
" + personColumn + @" = @PersonId,
PickupCode = @PickupCode
WHERE OrderNumber = @OrderNumber";
using (SqlCommand cmd = new SqlCommand(orderSql, con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.Parameters.AddWithValue("@OrderDate", orderDate);
cmd.Parameters.AddWithValue("@DeliveryDate", deliveryDate);
cmd.Parameters.AddWithValue("@StatusId", statusId);
cmd.Parameters.AddWithValue("@PickupPointAddress", pickupPointId);
cmd.Parameters.AddWithValue("@PersonId", personId);
cmd.Parameters.AddWithValue("@PickupCode", pickupCode);
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = new SqlCommand("DELETE FROM OrderItems WHERE OrderNumber = @OrderNumber", con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.ExecuteNonQuery();
}
foreach (OrderItemView item in items)
{
string itemSql = @"
INSERT INTO OrderItems
(OrderNumber, ProductArticleNumber, Quantity)
VALUES
(@OrderNumber, @ProductArticleNumber, @Quantity)";
using (SqlCommand cmd = new SqlCommand(itemSql, con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.Parameters.AddWithValue("@ProductArticleNumber", item.ProductArticleNumber);
cmd.Parameters.AddWithValue("@Quantity", item.Quantity);
cmd.ExecuteNonQuery();
}
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
public void DeleteOrder(int orderNumber)
{
using (SqlConnection con = Open())
using (SqlTransaction transaction = con.BeginTransaction())
{
try
{
using (SqlCommand cmd = new SqlCommand("DELETE FROM OrderItems WHERE OrderNumber = @OrderNumber", con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = new SqlCommand("DELETE FROM Orders WHERE OrderNumber = @OrderNumber", con, transaction))
{
cmd.Parameters.AddWithValue("@OrderNumber", orderNumber);
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
}
📄 LoginForm.Designer.cs
using System.Drawing;
using System.Windows.Forms;
namespace ToysStore
{
partial class LoginForm
{
private System.ComponentModel.IContainer components = null;
private Label lblTitle;
private Label lblLogin;
private Label lblPassword;
private TextBox txtLogin;
private TextBox txtPassword;
private Button btnLogin;
private Button btnGuest;
private PictureBox pictureLogo;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.lblTitle = new System.Windows.Forms.Label();
this.lblLogin = new System.Windows.Forms.Label();
this.lblPassword = new System.Windows.Forms.Label();
this.txtLogin = new System.Windows.Forms.TextBox();
this.txtPassword = new System.Windows.Forms.TextBox();
this.btnLogin = new System.Windows.Forms.Button();
this.btnGuest = new System.Windows.Forms.Button();
this.pictureLogo = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureLogo)).BeginInit();
this.SuspendLayout();
//
// lblTitle
//
this.lblTitle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.lblTitle.Dock = System.Windows.Forms.DockStyle.Top;
this.lblTitle.Font = new System.Drawing.Font("Times New Roman", 20F, System.Drawing.FontStyle.Bold);
this.lblTitle.Location = new System.Drawing.Point(0, 0);
this.lblTitle.Name = "lblTitle";
this.lblTitle.Size = new System.Drawing.Size(500, 60);
this.lblTitle.TabIndex = 0;
this.lblTitle.Text = "ООО \"Магазин игрушек\"";
this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.lblTitle.Click += new System.EventHandler(this.lblTitle_Click);
//
// lblLogin
//
this.lblLogin.Location = new System.Drawing.Point(80, 190);
this.lblLogin.Name = "lblLogin";
this.lblLogin.Size = new System.Drawing.Size(300, 25);
this.lblLogin.TabIndex = 2;
this.lblLogin.Text = "Логин";
//
// lblPassword
//
this.lblPassword.Location = new System.Drawing.Point(80, 260);
this.lblPassword.Name = "lblPassword";
this.lblPassword.Size = new System.Drawing.Size(300, 25);
this.lblPassword.TabIndex = 4;
this.lblPassword.Text = "Пароль";
//
// txtLogin
//
this.txtLogin.Location = new System.Drawing.Point(80, 220);
this.txtLogin.Name = "txtLogin";
this.txtLogin.Size = new System.Drawing.Size(330, 30);
this.txtLogin.TabIndex = 3;
//
// txtPassword
//
this.txtPassword.Location = new System.Drawing.Point(80, 290);
this.txtPassword.Name = "txtPassword";
this.txtPassword.PasswordChar = '*';
this.txtPassword.Size = new System.Drawing.Size(330, 30);
this.txtPassword.TabIndex = 5;
//
// btnLogin
//
this.btnLogin.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnLogin.Location = new System.Drawing.Point(80, 335);
this.btnLogin.Name = "btnLogin";
this.btnLogin.Size = new System.Drawing.Size(150, 35);
this.btnLogin.TabIndex = 6;
this.btnLogin.Text = "Войти";
this.btnLogin.UseVisualStyleBackColor = false;
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
//
// btnGuest
//
this.btnGuest.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.btnGuest.Location = new System.Drawing.Point(250, 335);
this.btnGuest.Name = "btnGuest";
this.btnGuest.Size = new System.Drawing.Size(160, 35);
this.btnGuest.TabIndex = 7;
this.btnGuest.Text = "Войти как гость";
this.btnGuest.UseVisualStyleBackColor = false;
this.btnGuest.Click += new System.EventHandler(this.btnGuest_Click);
//
// pictureLogo
//
this.pictureLogo.Location = new System.Drawing.Point(190, 80);
this.pictureLogo.Name = "pictureLogo";
this.pictureLogo.Size = new System.Drawing.Size(120, 90);
this.pictureLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureLogo.TabIndex = 1;
this.pictureLogo.TabStop = false;
//
// LoginForm
//
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(500, 420);
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.pictureLogo);
this.Controls.Add(this.lblLogin);
this.Controls.Add(this.txtLogin);
this.Controls.Add(this.lblPassword);
this.Controls.Add(this.txtPassword);
this.Controls.Add(this.btnLogin);
this.Controls.Add(this.btnGuest);
this.Font = new System.Drawing.Font("Times New Roman", 12F);
this.Name = "LoginForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ООО Магазин игрушек - вход";
((System.ComponentModel.ISupportInitialize)(this.pictureLogo)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
}
}
📄 LoginForm.cs
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace ToysStore
{
public partial class LoginForm : Form
{
private Db db = new Db();
public LoginForm()
{
InitializeComponent();
LoadBrandAssets();
}
private void LoadBrandAssets()
{
LoadFormIcon();
string logoPath = Path.Combine(Application.StartupPath, "Images", "Icon.png");
if (!File.Exists(logoPath))
return;
try
{
using (FileStream fs = new FileStream(logoPath, FileMode.Open, FileAccess.Read))
using (Image temp = Image.FromStream(fs))
{
pictureLogo.Image = new Bitmap(temp);
}
}
catch
{
pictureLogo.Image = null;
}
}
private void LoadFormIcon()
{
string iconPath = Path.Combine(Application.StartupPath, "Images", "Icon.ico");
if (!File.Exists(iconPath))
return;
try
{
Icon = new Icon(iconPath);
}
catch
{
Icon = null;
}
}
private void btnLogin_Click(object sender, EventArgs e)
{
if (txtLogin.Text.Trim() == "")
{
MessageHelper.Warning(
"Не введен логин.\n\n" +
"Введите логин пользователя или войдите как гость.");
txtLogin.Focus();
return;
}
if (txtPassword.Text.Trim() == "")
{
MessageHelper.Warning(
"Не введен пароль.\n\n" +
"Введите пароль пользователя или войдите как гость.");
txtPassword.Focus();
return;
}
try
{
CurrentUser user = db.Login(txtLogin.Text.Trim(), txtPassword.Text);
if (user == null)
{
MessageHelper.Warning(
"Неверный логин или пароль.\n\n" +
"Проверьте правильность введенных данных и попробуйте снова.\n" +
"Если у вас нет учетной записи, используйте вход как гость.");
return;
}
ProductsForm form = new ProductsForm(user);
// Окно входа прячется, чтобы после выхода из аккаунта снова показать его через Show().
Hide();
form.ShowDialog();
Show();
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось подключиться к базе данных.\n\n" +
"Проверьте, что SQL Server запущен, база данных существует, " +
"а строка подключения указана правильно.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
private void btnGuest_Click(object sender, EventArgs e)
{
ProductsForm form = new ProductsForm(new CurrentUser());
Hide();
form.ShowDialog();
Show();
}
}
}
📄 OrderEditForm.Designer.cs
using System.Drawing;
using System.Windows.Forms;
namespace ToysStore
{
partial class OrderEditForm
{
private System.ComponentModel.IContainer components = null;
private Label lblTitle;
private Label lblNumber;
private Label lblOrderDate;
private Label lblDeliveryDate;
private Label lblClient;
private Label lblPickupPoint;
private Label lblPickupCode;
private Label lblStatus;
private Label lblProduct;
private Label lblQuantity;
private Label lblTotal;
private TextBox txtNumber;
private TextBox txtPickupCode;
private TextBox txtQuantity;
private DateTimePicker dtpOrderDate;
private DateTimePicker dtpDeliveryDate;
private ComboBox cmbClient;
private ComboBox cmbPickupPoint;
private ComboBox cmbStatus;
private ComboBox cmbProduct;
private DataGridView gridItems;
private Button btnAddItem;
private Button btnRemoveItem;
private Button btnSave;
private Button btnCancel;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.lblTitle = new System.Windows.Forms.Label();
this.lblNumber = new System.Windows.Forms.Label();
this.lblOrderDate = new System.Windows.Forms.Label();
this.lblDeliveryDate = new System.Windows.Forms.Label();
this.lblClient = new System.Windows.Forms.Label();
this.lblPickupPoint = new System.Windows.Forms.Label();
this.lblPickupCode = new System.Windows.Forms.Label();
this.lblStatus = new System.Windows.Forms.Label();
this.lblProduct = new System.Windows.Forms.Label();
this.lblQuantity = new System.Windows.Forms.Label();
this.lblTotal = new System.Windows.Forms.Label();
this.txtNumber = new System.Windows.Forms.TextBox();
this.txtPickupCode = new System.Windows.Forms.TextBox();
this.txtQuantity = new System.Windows.Forms.TextBox();
this.dtpOrderDate = new System.Windows.Forms.DateTimePicker();
this.dtpDeliveryDate = new System.Windows.Forms.DateTimePicker();
this.cmbClient = new System.Windows.Forms.ComboBox();
this.cmbPickupPoint = new System.Windows.Forms.ComboBox();
this.cmbStatus = new System.Windows.Forms.ComboBox();
this.cmbProduct = new System.Windows.Forms.ComboBox();
this.gridItems = new System.Windows.Forms.DataGridView();
this.btnAddItem = new System.Windows.Forms.Button();
this.btnRemoveItem = new System.Windows.Forms.Button();
this.btnSave = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.gridItems)).BeginInit();
this.SuspendLayout();
//
// lblTitle
//
this.lblTitle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.lblTitle.Dock = System.Windows.Forms.DockStyle.Top;
this.lblTitle.Font = new System.Drawing.Font("Times New Roman", 16F, System.Drawing.FontStyle.Bold);
this.lblTitle.Location = new System.Drawing.Point(0, 0);
this.lblTitle.Name = "lblTitle";
this.lblTitle.Padding = new System.Windows.Forms.Padding(10, 0, 0, 0);
this.lblTitle.Size = new System.Drawing.Size(979, 45);
this.lblTitle.TabIndex = 0;
this.lblTitle.Text = "Заказ";
this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblNumber
//
this.lblNumber.Location = new System.Drawing.Point(20, 65);
this.lblNumber.Name = "lblNumber";
this.lblNumber.Size = new System.Drawing.Size(120, 25);
this.lblNumber.TabIndex = 1;
this.lblNumber.Text = "Номер:";
//
// lblOrderDate
//
this.lblOrderDate.Location = new System.Drawing.Point(20, 105);
this.lblOrderDate.Name = "lblOrderDate";
this.lblOrderDate.Size = new System.Drawing.Size(120, 25);
this.lblOrderDate.TabIndex = 5;
this.lblOrderDate.Text = "Дата заказа:";
//
// lblDeliveryDate
//
this.lblDeliveryDate.Location = new System.Drawing.Point(360, 105);
this.lblDeliveryDate.Name = "lblDeliveryDate";
this.lblDeliveryDate.Size = new System.Drawing.Size(130, 25);
this.lblDeliveryDate.TabIndex = 7;
this.lblDeliveryDate.Text = "Дата доставки:";
//
// lblClient
//
this.lblClient.Location = new System.Drawing.Point(20, 145);
this.lblClient.Name = "lblClient";
this.lblClient.Size = new System.Drawing.Size(120, 25);
this.lblClient.TabIndex = 9;
this.lblClient.Text = "Пользователь:";
//
// lblPickupPoint
//
this.lblPickupPoint.Location = new System.Drawing.Point(470, 145);
this.lblPickupPoint.Name = "lblPickupPoint";
this.lblPickupPoint.Size = new System.Drawing.Size(120, 25);
this.lblPickupPoint.TabIndex = 11;
this.lblPickupPoint.Text = "Пункт выдачи:";
//
// lblPickupCode
//
this.lblPickupCode.Location = new System.Drawing.Point(360, 65);
this.lblPickupCode.Name = "lblPickupCode";
this.lblPickupCode.Size = new System.Drawing.Size(130, 25);
this.lblPickupCode.TabIndex = 3;
this.lblPickupCode.Text = "Код получения:";
//
// lblStatus
//
this.lblStatus.Location = new System.Drawing.Point(700, 65);
this.lblStatus.Name = "lblStatus";
this.lblStatus.Size = new System.Drawing.Size(70, 25);
this.lblStatus.TabIndex = 23;
this.lblStatus.Text = "Статус:";
//
// lblProduct
//
this.lblProduct.BackColor = System.Drawing.Color.Transparent;
this.lblProduct.Location = new System.Drawing.Point(20, 187);
this.lblProduct.Name = "lblProduct";
this.lblProduct.Size = new System.Drawing.Size(66, 25);
this.lblProduct.TabIndex = 13;
this.lblProduct.Text = "Товар:";
//
// lblQuantity
//
this.lblQuantity.Location = new System.Drawing.Point(530, 190);
this.lblQuantity.Name = "lblQuantity";
this.lblQuantity.Size = new System.Drawing.Size(70, 25);
this.lblQuantity.TabIndex = 15;
this.lblQuantity.Text = "Кол-во:";
//
// lblTotal
//
this.lblTotal.Font = new System.Drawing.Font("Times New Roman", 12F, System.Drawing.FontStyle.Bold);
this.lblTotal.Location = new System.Drawing.Point(20, 570);
this.lblTotal.Name = "lblTotal";
this.lblTotal.Size = new System.Drawing.Size(300, 25);
this.lblTotal.TabIndex = 20;
this.lblTotal.Text = "Итого: 0 руб.";
//
// txtNumber
//
this.txtNumber.Location = new System.Drawing.Point(150, 62);
this.txtNumber.Name = "txtNumber";
this.txtNumber.ReadOnly = true;
this.txtNumber.Size = new System.Drawing.Size(180, 29);
this.txtNumber.TabIndex = 2;
//
// txtPickupCode
//
this.txtPickupCode.Location = new System.Drawing.Point(500, 62);
this.txtPickupCode.Name = "txtPickupCode";
this.txtPickupCode.Size = new System.Drawing.Size(180, 29);
this.txtPickupCode.TabIndex = 4;
//
// txtQuantity
//
this.txtQuantity.Location = new System.Drawing.Point(600, 187);
this.txtQuantity.Name = "txtQuantity";
this.txtQuantity.Size = new System.Drawing.Size(80, 29);
this.txtQuantity.TabIndex = 16;
this.txtQuantity.Text = "1";
//
// dtpOrderDate
//
this.dtpOrderDate.Location = new System.Drawing.Point(150, 102);
this.dtpOrderDate.Name = "dtpOrderDate";
this.dtpOrderDate.Size = new System.Drawing.Size(180, 29);
this.dtpOrderDate.TabIndex = 6;
//
// dtpDeliveryDate
//
this.dtpDeliveryDate.Location = new System.Drawing.Point(500, 102);
this.dtpDeliveryDate.Name = "dtpDeliveryDate";
this.dtpDeliveryDate.Size = new System.Drawing.Size(180, 29);
this.dtpDeliveryDate.TabIndex = 8;
//
// cmbClient
//
this.cmbClient.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbClient.Location = new System.Drawing.Point(150, 142);
this.cmbClient.Name = "cmbClient";
this.cmbClient.Size = new System.Drawing.Size(300, 28);
this.cmbClient.TabIndex = 10;
//
// cmbPickupPoint
//
this.cmbPickupPoint.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbPickupPoint.Location = new System.Drawing.Point(600, 142);
this.cmbPickupPoint.Name = "cmbPickupPoint";
this.cmbPickupPoint.Size = new System.Drawing.Size(355, 28);
this.cmbPickupPoint.TabIndex = 12;
//
// cmbStatus
//
this.cmbStatus.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbStatus.Location = new System.Drawing.Point(775, 62);
this.cmbStatus.Name = "cmbStatus";
this.cmbStatus.Size = new System.Drawing.Size(180, 28);
this.cmbStatus.TabIndex = 24;
//
// cmbProduct
//
this.cmbProduct.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbProduct.Location = new System.Drawing.Point(92, 188);
this.cmbProduct.Name = "cmbProduct";
this.cmbProduct.Size = new System.Drawing.Size(418, 28);
this.cmbProduct.TabIndex = 14;
//
// gridItems
//
this.gridItems.AllowUserToAddRows = false;
this.gridItems.AllowUserToDeleteRows = false;
this.gridItems.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.gridItems.BackgroundColor = System.Drawing.Color.White;
this.gridItems.ColumnHeadersHeight = 29;
this.gridItems.Location = new System.Drawing.Point(20, 230);
this.gridItems.MultiSelect = false;
this.gridItems.Name = "gridItems";
this.gridItems.ReadOnly = true;
this.gridItems.RowHeadersWidth = 51;
this.gridItems.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.gridItems.Size = new System.Drawing.Size(935, 330);
this.gridItems.TabIndex = 19;
//
// btnAddItem
//
this.btnAddItem.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnAddItem.Location = new System.Drawing.Point(700, 185);
this.btnAddItem.Name = "btnAddItem";
this.btnAddItem.Size = new System.Drawing.Size(130, 32);
this.btnAddItem.TabIndex = 17;
this.btnAddItem.Text = "Добавить товар";
this.btnAddItem.UseVisualStyleBackColor = false;
this.btnAddItem.Click += new System.EventHandler(this.btnAddItem_Click);
//
// btnRemoveItem
//
this.btnRemoveItem.BackColor = System.Drawing.Color.LightCoral;
this.btnRemoveItem.Location = new System.Drawing.Point(835, 185);
this.btnRemoveItem.Name = "btnRemoveItem";
this.btnRemoveItem.Size = new System.Drawing.Size(120, 32);
this.btnRemoveItem.TabIndex = 18;
this.btnRemoveItem.Text = "Удалить строку";
this.btnRemoveItem.UseVisualStyleBackColor = false;
this.btnRemoveItem.Click += new System.EventHandler(this.btnRemoveItem_Click);
//
// btnSave
//
this.btnSave.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnSave.Location = new System.Drawing.Point(689, 570);
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(130, 35);
this.btnSave.TabIndex = 21;
this.btnSave.Text = "Сохранить";
this.btnSave.UseVisualStyleBackColor = false;
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// btnCancel
//
this.btnCancel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.btnCancel.Location = new System.Drawing.Point(825, 570);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(130, 35);
this.btnCancel.TabIndex = 22;
this.btnCancel.Text = "Отмена";
this.btnCancel.UseVisualStyleBackColor = false;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// OrderEditForm
//
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(979, 650);
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.lblNumber);
this.Controls.Add(this.txtNumber);
this.Controls.Add(this.lblPickupCode);
this.Controls.Add(this.txtPickupCode);
this.Controls.Add(this.lblStatus);
this.Controls.Add(this.cmbStatus);
this.Controls.Add(this.lblOrderDate);
this.Controls.Add(this.dtpOrderDate);
this.Controls.Add(this.lblDeliveryDate);
this.Controls.Add(this.dtpDeliveryDate);
this.Controls.Add(this.lblClient);
this.Controls.Add(this.cmbClient);
this.Controls.Add(this.lblPickupPoint);
this.Controls.Add(this.cmbPickupPoint);
this.Controls.Add(this.lblProduct);
this.Controls.Add(this.cmbProduct);
this.Controls.Add(this.lblQuantity);
this.Controls.Add(this.txtQuantity);
this.Controls.Add(this.btnAddItem);
this.Controls.Add(this.btnRemoveItem);
this.Controls.Add(this.gridItems);
this.Controls.Add(this.lblTotal);
this.Controls.Add(this.btnSave);
this.Controls.Add(this.btnCancel);
this.Font = new System.Drawing.Font("Times New Roman", 11F);
this.Name = "OrderEditForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Заказ";
((System.ComponentModel.ISupportInitialize)(this.gridItems)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
}
}
📄 OrderEditForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace ToysStore
{
public partial class OrderEditForm : Form
{
private Db db = new Db();
private OrderView order;
private bool isNew;
private List<Product> products = new List<Product>();
private List<OrderItemView> items = new List<OrderItemView>();
// BindingSource нужен, чтобы DataGridView нормально обновлялся после изменения списка items.
private BindingSource itemsBindingSource = new BindingSource();
public OrderEditForm(OrderView selectedOrder)
{
order = selectedOrder;
isNew = order == null;
InitializeComponent();
LoadFormIcon();
try
{
LoadLookups();
if (isNew)
PrepareNewOrder();
else
LoadExistingOrder();
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось открыть форму заказа.\n\n" +
"Проверьте подключение к базе данных и наличие справочников пользователей, пунктов выдачи и товаров.\n\n" +
"Техническая информация:\n" + ex.Message);
Close();
}
}
private void LoadFormIcon()
{
string iconPath = Path.Combine(Application.StartupPath, "Images", "Icon.ico");
if (!File.Exists(iconPath))
return;
try
{
Icon = new Icon(iconPath);
}
catch
{
Icon = null;
}
}
private void LoadLookups()
{
cmbClient.DataSource = db.GetLookup("Persons");
cmbClient.DisplayMember = "Name";
cmbClient.ValueMember = "Id";
cmbPickupPoint.DataSource = db.GetLookup("PickupPoints");
cmbPickupPoint.DisplayMember = "Name";
cmbPickupPoint.ValueMember = "Id";
cmbStatus.DataSource = db.GetLookup("OrderStatuses");
cmbStatus.DisplayMember = "Name";
cmbStatus.ValueMember = "Id";
products = db.GetProducts();
cmbProduct.DataSource = products;
cmbProduct.DisplayMember = "DisplayText";
cmbProduct.ValueMember = "ArticleNumber";
}
private void PrepareNewOrder()
{
lblTitle.Text = "Добавление заказа";
txtNumber.Text = db.GetNextOrderNumber().ToString();
txtPickupCode.Text = new Random().Next(100, 999).ToString();
dtpOrderDate.Value = DateTime.Today;
dtpDeliveryDate.Value = DateTime.Today.AddDays(3);
cmbStatus.SelectedValue = 2;
RenderItems();
}
private void LoadExistingOrder()
{
lblTitle.Text = "Редактирование заказа №" + order.OrderNumber;
txtNumber.Text = order.OrderNumber.ToString();
txtPickupCode.Text = order.PickupCode.ToString();
cmbClient.SelectedValue = order.PersonId;
cmbPickupPoint.SelectedValue = order.PickupPointId;
cmbStatus.SelectedValue = order.StatusId;
DateTime orderDate;
if (DateTime.TryParse(order.OrderDate, out orderDate))
dtpOrderDate.Value = orderDate;
DateTime deliveryDate;
if (DateTime.TryParse(order.DeliveryDate, out deliveryDate))
dtpDeliveryDate.Value = deliveryDate;
items = db.GetOrderItems(order.OrderNumber);
RenderItems();
}
private void btnAddItem_Click(object sender, EventArgs e)
{
if (cmbProduct.SelectedItem == null)
{
MessageHelper.Warning(
"Товар не выбран.\n\n" +
"Выберите товар из списка и повторите добавление.");
return;
}
double quantity;
if (!double.TryParse(txtQuantity.Text, out quantity) || quantity <= 0)
{
MessageHelper.Warning(
"Некорректное количество товара.\n\n" +
"Введите число больше 0. Например: 1 или 2.");
txtQuantity.Focus();
return;
}
Product product = cmbProduct.SelectedItem as Product;
if (product == null)
{
MessageHelper.Warning(
"Не удалось определить выбранный товар.\n\n" +
"Выберите товар из списка повторно.");
return;
}
OrderItemView existing = items.FirstOrDefault(x => x.ProductArticleNumber == product.ArticleNumber);
if (existing != null)
{
existing.Quantity += quantity;
}
else
{
items.Add(new OrderItemView
{
ProductArticleNumber = product.ArticleNumber,
ProductName = product.ProductName,
Quantity = quantity,
Price = product.Price,
Discount = product.CurrentDiscount
});
}
RenderItems();
}
private void btnRemoveItem_Click(object sender, EventArgs e)
{
if (gridItems.SelectedRows.Count == 0 && gridItems.CurrentRow == null)
{
MessageHelper.Warning(
"Строка состава заказа не выбрана.\n\n" +
"Выберите товар в таблице состава заказа и повторите удаление.");
return;
}
DataGridViewRow selectedRow = gridItems.SelectedRows.Count > 0
? gridItems.SelectedRows[0]
: gridItems.CurrentRow;
// Удаляем именно объект из привязанного списка, а не просто визуальную строку таблицы.
OrderItemView item = selectedRow.DataBoundItem as OrderItemView;
if (item == null)
{
MessageHelper.Warning(
"Не удалось найти выбранный товар в составе заказа.\n\n" +
"Обновите форму и повторите действие.");
return;
}
if (MessageHelper.Confirm(
"Удалить товар \"" + item.ProductName + "\" из состава заказа?\n\n" +
"Это действие изменит итоговую сумму заказа."))
{
items.Remove(item);
RenderItems();
}
}
private void RenderItems()
{
ConfigureItemsGrid();
itemsBindingSource.DataSource = null;
itemsBindingSource.DataSource = items;
gridItems.DataSource = itemsBindingSource;
gridItems.ClearSelection();
lblTotal.Text = "Итого: " + items.Sum(x => x.Total).ToString("N2") + " руб.";
}
private void ConfigureItemsGrid()
{
if (gridItems.Columns.Count > 0)
return;
gridItems.AutoGenerateColumns = false;
AddGridColumn("ProductArticleNumber", "Артикул", "ProductArticleNumber");
AddGridColumn("ProductName", "Товар", "ProductName");
AddGridColumn("Quantity", "Количество", "Quantity");
AddGridColumn("Price", "Цена", "Price");
AddGridColumn("Discount", "Скидка", "Discount");
AddGridColumn("Total", "Сумма", "Total");
}
private void AddGridColumn(string name, string header, string propertyName)
{
DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
column.Name = name;
column.HeaderText = header;
column.DataPropertyName = propertyName;
column.ReadOnly = true;
gridItems.Columns.Add(column);
}
private void btnSave_Click(object sender, EventArgs e)
{
if (items.Count == 0)
{
MessageHelper.Warning(
"В заказе нет товаров.\n\n" +
"Добавьте хотя бы один товар в состав заказа и повторите сохранение.");
return;
}
int pickupCode;
if (!int.TryParse(txtPickupCode.Text, out pickupCode))
{
MessageHelper.Warning(
"Некорректный код получения.\n\n" +
"Введите числовой код получения, например 123.");
txtPickupCode.Focus();
return;
}
if (cmbClient.SelectedValue == null)
{
MessageHelper.Warning(
"Не выбран пользователь.\n\n" +
"Выберите пользователя из списка.");
return;
}
if (cmbPickupPoint.SelectedValue == null)
{
MessageHelper.Warning(
"Не выбран пункт выдачи.\n\n" +
"Выберите пункт выдачи из списка.");
return;
}
if (cmbStatus.SelectedValue == null)
{
MessageHelper.Warning(
"Не выбран статус заказа.\n\n" +
"Выберите статус заказа из списка.");
return;
}
if (dtpDeliveryDate.Value.Date < dtpOrderDate.Value.Date)
{
MessageHelper.Warning(
"Дата доставки не может быть раньше даты заказа.\n\n" +
"Измените дату доставки и повторите сохранение.");
dtpDeliveryDate.Focus();
return;
}
try
{
int orderNumber = Convert.ToInt32(txtNumber.Text);
int personId = Convert.ToInt32(cmbClient.SelectedValue);
int pickupPointId = Convert.ToInt32(cmbPickupPoint.SelectedValue);
int statusId = Convert.ToInt32(cmbStatus.SelectedValue);
if (isNew)
{
db.AddOrder(
orderNumber,
dtpOrderDate.Value,
dtpDeliveryDate.Value,
statusId,
pickupPointId,
personId,
pickupCode,
items);
}
else
{
db.UpdateOrder(
orderNumber,
dtpOrderDate.Value,
dtpDeliveryDate.Value,
statusId,
pickupPointId,
personId,
pickupCode,
items);
}
MessageHelper.Info("Заказ успешно сохранен.");
DialogResult = DialogResult.OK;
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось сохранить заказ.\n\n" +
"Проверьте заполнение всех полей, наличие товаров в заказе " +
"и подключение к базе данных.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}
📄 OrdersForm.Designer.cs
using System.Drawing;
using System.Windows.Forms;
namespace ToysStore
{
partial class OrdersForm
{
private System.ComponentModel.IContainer components = null;
private Label lblHeader;
private FlowLayoutPanel panelOrders;
private Panel panelButtons;
private Button btnAdd;
private Button btnEdit;
private Button btnDelete;
private Button btnRefresh;
private Button btnBack;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.lblHeader = new Label();
this.panelOrders = new FlowLayoutPanel();
this.panelButtons = new Panel();
this.btnAdd = new Button();
this.btnEdit = new Button();
this.btnDelete = new Button();
this.btnRefresh = new Button();
this.btnBack = new Button();
this.SuspendLayout();
this.Text = "Заказы";
this.ClientSize = new Size(1000, 650);
this.StartPosition = FormStartPosition.CenterScreen;
this.Font = new Font("Times New Roman", 11F);
this.BackColor = Color.White;
this.lblHeader.Text = "Заказы";
this.lblHeader.Dock = DockStyle.Top;
this.lblHeader.Height = 45;
this.lblHeader.Font = new Font("Times New Roman", 16F, FontStyle.Bold);
this.lblHeader.BackColor = ColorTranslator.FromHtml("#7FFF00");
this.lblHeader.TextAlign = ContentAlignment.MiddleLeft;
this.lblHeader.Padding = new Padding(10, 0, 0, 0);
this.panelButtons.Dock = DockStyle.Bottom;
this.panelButtons.Height = 55;
this.panelButtons.BackColor = Color.White;
this.btnAdd.Text = "Добавить заказ";
this.btnAdd.Location = new Point(10, 12);
this.btnAdd.Size = new Size(140, 32);
this.btnAdd.BackColor = ColorTranslator.FromHtml("#00FA9A");
this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
this.btnEdit.Text = "Редактировать";
this.btnEdit.Location = new Point(160, 12);
this.btnEdit.Size = new Size(130, 32);
this.btnEdit.BackColor = ColorTranslator.FromHtml("#00FA9A");
this.btnEdit.Click += new System.EventHandler(this.btnEdit_Click);
this.btnDelete.Text = "Удалить";
this.btnDelete.Location = new Point(300, 12);
this.btnDelete.Size = new Size(110, 32);
this.btnDelete.BackColor = Color.LightCoral;
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
this.btnRefresh.Text = "Обновить";
this.btnRefresh.Location = new Point(420, 12);
this.btnRefresh.Size = new Size(110, 32);
this.btnRefresh.BackColor = ColorTranslator.FromHtml("#00FA9A");
this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
this.btnBack.Text = "Назад";
this.btnBack.Location = new Point(540, 12);
this.btnBack.Size = new Size(110, 32);
this.btnBack.BackColor = ColorTranslator.FromHtml("#7FFF00");
this.btnBack.Click += new System.EventHandler(this.btnBack_Click);
this.panelButtons.Controls.Add(this.btnAdd);
this.panelButtons.Controls.Add(this.btnEdit);
this.panelButtons.Controls.Add(this.btnDelete);
this.panelButtons.Controls.Add(this.btnRefresh);
this.panelButtons.Controls.Add(this.btnBack);
this.panelOrders.Dock = DockStyle.Fill;
this.panelOrders.AutoScroll = true;
this.panelOrders.BackColor = Color.White;
this.panelOrders.Padding = new Padding(15);
this.panelOrders.FlowDirection = FlowDirection.TopDown;
this.panelOrders.WrapContents = false;
this.Controls.Add(this.panelOrders);
this.Controls.Add(this.panelButtons);
this.Controls.Add(this.lblHeader);
this.ResumeLayout(false);
}
}
}
📄 OrdersForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace ToysStore
{
public partial class OrdersForm : Form
{
private Db db = new Db();
private CurrentUser user;
private List<OrderView> orders = new List<OrderView>();
public OrdersForm(CurrentUser currentUser)
{
user = currentUser;
InitializeComponent();
LoadFormIcon();
bool isAdmin = user.Role == UserRole.Admin;
// Управление заказами доступно только администратору.
btnAdd.Visible = isAdmin;
btnEdit.Visible = isAdmin;
btnDelete.Visible = isAdmin;
LoadOrders();
}
private void LoadFormIcon()
{
string iconPath = Path.Combine(Application.StartupPath, "Images", "Icon.ico");
if (!File.Exists(iconPath))
return;
try
{
Icon = new Icon(iconPath);
}
catch
{
Icon = null;
}
}
private void LoadOrders()
{
try
{
orders = db.GetOrders();
lblHeader.Text = "Заказы | " + orders.Count + " записей";
panelOrders.Controls.Clear();
panelOrders.Tag = null;
foreach (OrderView order in orders)
{
panelOrders.Controls.Add(CreateOrderCard(order));
}
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось загрузить список заказов.\n\n" +
"Проверьте подключение к базе данных и наличие таблиц Orders, OrderItems, Products, Persons, PickupPoints.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
private Panel CreateOrderCard(OrderView order)
{
// Карточка повторяет макет задания; дополнительные поля оставлены в левом блоке.
Panel outerCard = new Panel();
outerCard.Width = 900;
outerCard.Height = 155;
outerCard.Margin = new Padding(5, 5, 5, 12);
outerCard.BorderStyle = BorderStyle.FixedSingle;
outerCard.BackColor = Color.White;
outerCard.Tag = order;
Panel leftBlock = new Panel();
leftBlock.Location = new Point(25, 17);
leftBlock.Size = new Size(675, 115);
leftBlock.BorderStyle = BorderStyle.FixedSingle;
leftBlock.BackColor = Color.White;
leftBlock.Tag = order;
Panel rightBlock = new Panel();
rightBlock.Location = new Point(725, 17);
rightBlock.Size = new Size(145, 115);
rightBlock.BorderStyle = BorderStyle.FixedSingle;
rightBlock.BackColor = Color.White;
rightBlock.Tag = order;
Label lblLeft = new Label();
lblLeft.Location = new Point(10, 8);
lblLeft.Size = new Size(650, 102);
lblLeft.Font = new Font("Times New Roman", 11F, FontStyle.Bold);
lblLeft.Text =
"Артикул заказа: " + order.OrderNumber + "\n" +
"Статус заказа: " + order.StatusName + "\n" +
"Адрес пункта выдачи: " + order.PickupAddress + "\n" +
"Дата заказа: " + order.OrderDate + "\n" +
"Пользователь: " + order.PersonName + " | Код: " + order.PickupCode + " | Сумма: " + order.Total.ToString("N2") + " руб.";
lblLeft.AutoEllipsis = true;
lblLeft.Tag = order;
Label lblRightTitle = new Label();
lblRightTitle.Location = new Point(8, 10);
lblRightTitle.Size = new Size(125, 25);
lblRightTitle.Font = new Font("Times New Roman", 11F, FontStyle.Bold);
lblRightTitle.Text = "Дата доставки";
lblRightTitle.TextAlign = ContentAlignment.MiddleCenter;
lblRightTitle.Tag = order;
Label lblDeliveryDate = new Label();
lblDeliveryDate.Location = new Point(8, 42);
lblDeliveryDate.Size = new Size(125, 48);
lblDeliveryDate.Font = new Font("Times New Roman", 11F, FontStyle.Regular);
lblDeliveryDate.Text = order.DeliveryDate;
lblDeliveryDate.TextAlign = ContentAlignment.MiddleCenter;
lblDeliveryDate.Tag = order;
leftBlock.Controls.Add(lblLeft);
rightBlock.Controls.Add(lblRightTitle);
rightBlock.Controls.Add(lblDeliveryDate);
outerCard.Controls.Add(leftBlock);
outerCard.Controls.Add(rightBlock);
AddCardEvents(outerCard, outerCard);
AddCardEvents(leftBlock, outerCard);
AddCardEvents(rightBlock, outerCard);
AddCardEvents(lblLeft, outerCard);
AddCardEvents(lblRightTitle, outerCard);
AddCardEvents(lblDeliveryDate, outerCard);
return outerCard;
}
private void AddCardEvents(Control control, Panel card)
{
control.Click += delegate
{
SelectCard(card);
};
control.DoubleClick += delegate
{
SelectCard(card);
if (user.Role == UserRole.Admin)
OpenEditForm(card.Tag as OrderView);
};
}
private void SelectCard(Panel selected)
{
foreach (Control control in panelOrders.Controls)
{
control.BackColor = Color.White;
foreach (Control child in control.Controls)
{
child.BackColor = Color.White;
foreach (Control innerChild in child.Controls)
{
innerChild.BackColor = Color.White;
}
}
}
selected.BackColor = ColorTranslator.FromHtml("#00FA9A");
panelOrders.Tag = selected.Tag;
}
private OrderView GetSelectedOrder()
{
return panelOrders.Tag as OrderView;
}
private void OpenEditForm(OrderView order)
{
if (order == null)
return;
OrderEditForm form = new OrderEditForm(order);
if (form.ShowDialog() == DialogResult.OK)
LoadOrders();
}
private void btnAdd_Click(object sender, EventArgs e)
{
OrderEditForm form = new OrderEditForm(null);
if (form.ShowDialog() == DialogResult.OK)
LoadOrders();
}
private void btnEdit_Click(object sender, EventArgs e)
{
OrderView order = GetSelectedOrder();
if (order == null)
{
MessageHelper.Warning(
"Заказ не выбран.\n\n" +
"Сначала нажмите на карточку заказа, затем повторите действие.");
return;
}
OpenEditForm(order);
}
private void btnDelete_Click(object sender, EventArgs e)
{
OrderView order = GetSelectedOrder();
if (order == null)
{
MessageHelper.Warning(
"Заказ не выбран.\n\n" +
"Сначала нажмите на карточку заказа, затем повторите действие.");
return;
}
if (MessageHelper.Confirm(
"Вы действительно хотите удалить заказ №" + order.OrderNumber + "?\n\n" +
"Будут удалены заказ и все товары из его состава. Это действие нельзя отменить."))
{
try
{
db.DeleteOrder(order.OrderNumber);
MessageHelper.Info("Заказ успешно удален.");
LoadOrders();
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось удалить заказ.\n\n" +
"Проверьте подключение к базе данных и повторите попытку.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
}
private void btnRefresh_Click(object sender, EventArgs e)
{
LoadOrders();
}
private void btnBack_Click(object sender, EventArgs e)
{
Close();
}
}
}
📄 ProductEditForm.Designer.cs
using System.Drawing;
using System.Windows.Forms;
namespace ToysStore
{
partial class ProductEditForm
{
private System.ComponentModel.IContainer components = null;
private Label lblArticle;
private Label lblName;
private Label lblUnit;
private Label lblPrice;
private Label lblSupplier;
private Label lblManufacturer;
private Label lblCategory;
private Label lblDiscount;
private Label lblStock;
private Label lblPhoto;
private Label lblDescription;
private TextBox txtArticle;
private TextBox txtName;
private TextBox txtPrice;
private TextBox txtDiscount;
private TextBox txtStock;
private TextBox txtPhoto;
private TextBox txtDescription;
private ComboBox cmbUnit;
private ComboBox cmbSupplier;
private ComboBox cmbManufacturer;
private ComboBox cmbCategory;
private Button btnSelectPhoto;
private Button btnSave;
private Button btnCancel;
private PictureBox picPhoto;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.lblArticle = new System.Windows.Forms.Label();
this.lblName = new System.Windows.Forms.Label();
this.lblUnit = new System.Windows.Forms.Label();
this.lblPrice = new System.Windows.Forms.Label();
this.lblSupplier = new System.Windows.Forms.Label();
this.lblManufacturer = new System.Windows.Forms.Label();
this.lblCategory = new System.Windows.Forms.Label();
this.lblDiscount = new System.Windows.Forms.Label();
this.lblStock = new System.Windows.Forms.Label();
this.lblPhoto = new System.Windows.Forms.Label();
this.lblDescription = new System.Windows.Forms.Label();
this.txtArticle = new System.Windows.Forms.TextBox();
this.txtName = new System.Windows.Forms.TextBox();
this.txtPrice = new System.Windows.Forms.TextBox();
this.txtDiscount = new System.Windows.Forms.TextBox();
this.txtStock = new System.Windows.Forms.TextBox();
this.txtPhoto = new System.Windows.Forms.TextBox();
this.txtDescription = new System.Windows.Forms.TextBox();
this.cmbUnit = new System.Windows.Forms.ComboBox();
this.cmbSupplier = new System.Windows.Forms.ComboBox();
this.cmbManufacturer = new System.Windows.Forms.ComboBox();
this.cmbCategory = new System.Windows.Forms.ComboBox();
this.btnSelectPhoto = new System.Windows.Forms.Button();
this.btnSave = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.picPhoto = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.picPhoto)).BeginInit();
this.SuspendLayout();
//
// lblArticle
//
this.lblArticle.Location = new System.Drawing.Point(38, 28);
this.lblArticle.Name = "lblArticle";
this.lblArticle.Size = new System.Drawing.Size(165, 28);
this.lblArticle.TabIndex = 0;
this.lblArticle.Text = "Артикул";
this.lblArticle.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblName
//
this.lblName.Location = new System.Drawing.Point(38, 72);
this.lblName.Name = "lblName";
this.lblName.Size = new System.Drawing.Size(165, 28);
this.lblName.TabIndex = 1;
this.lblName.Text = "Название";
this.lblName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblUnit
//
this.lblUnit.Location = new System.Drawing.Point(38, 116);
this.lblUnit.Name = "lblUnit";
this.lblUnit.Size = new System.Drawing.Size(165, 28);
this.lblUnit.TabIndex = 2;
this.lblUnit.Text = "Единица";
this.lblUnit.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblPrice
//
this.lblPrice.Location = new System.Drawing.Point(38, 160);
this.lblPrice.Name = "lblPrice";
this.lblPrice.Size = new System.Drawing.Size(165, 28);
this.lblPrice.TabIndex = 3;
this.lblPrice.Text = "Цена";
this.lblPrice.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblSupplier
//
this.lblSupplier.Location = new System.Drawing.Point(38, 204);
this.lblSupplier.Name = "lblSupplier";
this.lblSupplier.Size = new System.Drawing.Size(165, 28);
this.lblSupplier.TabIndex = 4;
this.lblSupplier.Text = "Поставщик";
this.lblSupplier.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblManufacturer
//
this.lblManufacturer.Location = new System.Drawing.Point(38, 248);
this.lblManufacturer.Name = "lblManufacturer";
this.lblManufacturer.Size = new System.Drawing.Size(165, 28);
this.lblManufacturer.TabIndex = 5;
this.lblManufacturer.Text = "Производитель";
this.lblManufacturer.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblCategory
//
this.lblCategory.Location = new System.Drawing.Point(38, 292);
this.lblCategory.Name = "lblCategory";
this.lblCategory.Size = new System.Drawing.Size(165, 28);
this.lblCategory.TabIndex = 6;
this.lblCategory.Text = "Категория";
this.lblCategory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblDiscount
//
this.lblDiscount.Location = new System.Drawing.Point(38, 336);
this.lblDiscount.Name = "lblDiscount";
this.lblDiscount.Size = new System.Drawing.Size(165, 28);
this.lblDiscount.TabIndex = 7;
this.lblDiscount.Text = "Скидка";
this.lblDiscount.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblStock
//
this.lblStock.Location = new System.Drawing.Point(38, 380);
this.lblStock.Name = "lblStock";
this.lblStock.Size = new System.Drawing.Size(165, 28);
this.lblStock.TabIndex = 8;
this.lblStock.Text = "Остаток";
this.lblStock.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblPhoto
//
this.lblPhoto.Location = new System.Drawing.Point(38, 424);
this.lblPhoto.Name = "lblPhoto";
this.lblPhoto.Size = new System.Drawing.Size(165, 28);
this.lblPhoto.TabIndex = 9;
this.lblPhoto.Text = "Фото";
this.lblPhoto.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblDescription
//
this.lblDescription.Location = new System.Drawing.Point(38, 468);
this.lblDescription.Name = "lblDescription";
this.lblDescription.Size = new System.Drawing.Size(165, 28);
this.lblDescription.TabIndex = 10;
this.lblDescription.Text = "Описание";
this.lblDescription.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// txtArticle
//
this.txtArticle.Location = new System.Drawing.Point(220, 24);
this.txtArticle.Name = "txtArticle";
this.txtArticle.Size = new System.Drawing.Size(560, 29);
this.txtArticle.TabIndex = 11;
//
// txtName
//
this.txtName.Location = new System.Drawing.Point(220, 68);
this.txtName.Name = "txtName";
this.txtName.Size = new System.Drawing.Size(560, 29);
this.txtName.TabIndex = 12;
//
// txtPrice
//
this.txtPrice.Location = new System.Drawing.Point(220, 156);
this.txtPrice.Name = "txtPrice";
this.txtPrice.Size = new System.Drawing.Size(560, 29);
this.txtPrice.TabIndex = 14;
//
// txtDiscount
//
this.txtDiscount.Location = new System.Drawing.Point(220, 332);
this.txtDiscount.Name = "txtDiscount";
this.txtDiscount.Size = new System.Drawing.Size(560, 29);
this.txtDiscount.TabIndex = 18;
//
// txtStock
//
this.txtStock.Location = new System.Drawing.Point(220, 376);
this.txtStock.Name = "txtStock";
this.txtStock.Size = new System.Drawing.Size(560, 29);
this.txtStock.TabIndex = 19;
//
// txtPhoto
//
this.txtPhoto.Location = new System.Drawing.Point(220, 420);
this.txtPhoto.Name = "txtPhoto";
this.txtPhoto.ReadOnly = true;
this.txtPhoto.Size = new System.Drawing.Size(360, 29);
this.txtPhoto.TabIndex = 20;
//
// txtDescription
//
this.txtDescription.Location = new System.Drawing.Point(220, 464);
this.txtDescription.Multiline = true;
this.txtDescription.Name = "txtDescription";
this.txtDescription.Size = new System.Drawing.Size(560, 62);
this.txtDescription.TabIndex = 22;
//
// cmbUnit
//
this.cmbUnit.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbUnit.Location = new System.Drawing.Point(220, 112);
this.cmbUnit.Name = "cmbUnit";
this.cmbUnit.Size = new System.Drawing.Size(560, 28);
this.cmbUnit.TabIndex = 13;
//
// cmbSupplier
//
this.cmbSupplier.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbSupplier.Location = new System.Drawing.Point(220, 200);
this.cmbSupplier.Name = "cmbSupplier";
this.cmbSupplier.Size = new System.Drawing.Size(560, 28);
this.cmbSupplier.TabIndex = 15;
//
// cmbManufacturer
//
this.cmbManufacturer.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbManufacturer.Location = new System.Drawing.Point(220, 244);
this.cmbManufacturer.Name = "cmbManufacturer";
this.cmbManufacturer.Size = new System.Drawing.Size(560, 28);
this.cmbManufacturer.TabIndex = 16;
//
// cmbCategory
//
this.cmbCategory.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCategory.Location = new System.Drawing.Point(220, 288);
this.cmbCategory.Name = "cmbCategory";
this.cmbCategory.Size = new System.Drawing.Size(560, 28);
this.cmbCategory.TabIndex = 17;
//
// btnSelectPhoto
//
this.btnSelectPhoto.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnSelectPhoto.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSelectPhoto.Location = new System.Drawing.Point(595, 418);
this.btnSelectPhoto.Name = "btnSelectPhoto";
this.btnSelectPhoto.Size = new System.Drawing.Size(125, 34);
this.btnSelectPhoto.TabIndex = 21;
this.btnSelectPhoto.Text = "Выбрать";
this.btnSelectPhoto.UseVisualStyleBackColor = false;
this.btnSelectPhoto.Click += new System.EventHandler(this.btnSelectPhoto_Click);
//
// btnSave
//
this.btnSave.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnSave.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSave.Location = new System.Drawing.Point(220, 555);
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(150, 38);
this.btnSave.TabIndex = 23;
this.btnSave.Text = "Сохранить";
this.btnSave.UseVisualStyleBackColor = false;
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// btnCancel
//
this.btnCancel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnCancel.Location = new System.Drawing.Point(395, 555);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(150, 38);
this.btnCancel.TabIndex = 24;
this.btnCancel.Text = "Отмена";
this.btnCancel.UseVisualStyleBackColor = false;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// picPhoto
//
this.picPhoto.BackColor = System.Drawing.Color.White;
this.picPhoto.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.picPhoto.Location = new System.Drawing.Point(786, 406);
this.picPhoto.Name = "picPhoto";
this.picPhoto.Size = new System.Drawing.Size(180, 120);
this.picPhoto.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picPhoto.TabIndex = 25;
this.picPhoto.TabStop = false;
//
// ProductEditForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(975, 620);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnSave);
this.Controls.Add(this.btnSelectPhoto);
this.Controls.Add(this.picPhoto);
this.Controls.Add(this.cmbCategory);
this.Controls.Add(this.cmbManufacturer);
this.Controls.Add(this.cmbSupplier);
this.Controls.Add(this.cmbUnit);
this.Controls.Add(this.txtDescription);
this.Controls.Add(this.txtPhoto);
this.Controls.Add(this.txtStock);
this.Controls.Add(this.txtDiscount);
this.Controls.Add(this.txtPrice);
this.Controls.Add(this.txtName);
this.Controls.Add(this.txtArticle);
this.Controls.Add(this.lblDescription);
this.Controls.Add(this.lblPhoto);
this.Controls.Add(this.lblStock);
this.Controls.Add(this.lblDiscount);
this.Controls.Add(this.lblCategory);
this.Controls.Add(this.lblManufacturer);
this.Controls.Add(this.lblSupplier);
this.Controls.Add(this.lblPrice);
this.Controls.Add(this.lblUnit);
this.Controls.Add(this.lblName);
this.Controls.Add(this.lblArticle);
this.Font = new System.Drawing.Font("Times New Roman", 11F);
this.MinimumSize = new System.Drawing.Size(978, 667);
this.Name = "ProductEditForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Товар";
((System.ComponentModel.ISupportInitialize)(this.picPhoto)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
}
}
📄 ProductEditForm.cs
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace ToysStore
{
public partial class ProductEditForm : Form
{
private readonly Db db = new Db();
private readonly Product product;
private readonly bool isNew;
private string selectedPhotoPath = "";
private string originalPhoto = "";
public ProductEditForm(Product selectedProduct)
{
product = selectedProduct;
isNew = product == null;
InitializeComponent();
LoadFormIcon();
Text = isNew ? "Добавление товара" : "Редактирование товара";
try
{
LoadLookups();
if (!isNew)
FillFields();
else
LoadPhotoPreview("");
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось загрузить данные для формы товара.\n\n" +
"Проверьте подключение к базе данных и наличие справочников: Units, Suppliers, Manufacturers, Categories.\n\n" +
"Техническая информация:\n" + ex.Message);
Close();
}
}
private void LoadFormIcon()
{
string iconPath = Path.Combine(Application.StartupPath, "Images", "Icon.ico");
if (!File.Exists(iconPath))
return;
try
{
Icon = new Icon(iconPath);
}
catch
{
Icon = null;
}
}
private void LoadLookups()
{
FillCombo(cmbUnit, "Units");
FillCombo(cmbSupplier, "Suppliers");
FillCombo(cmbManufacturer, "Manufacturers");
FillCombo(cmbCategory, "Categories");
}
private void FillCombo(ComboBox combo, string table)
{
combo.DataSource = db.GetLookup(table);
combo.DisplayMember = "Name";
combo.ValueMember = "Id";
}
private void FillFields()
{
txtArticle.Text = product.ArticleNumber;
txtArticle.ReadOnly = true;
txtName.Text = product.ProductName;
cmbUnit.SelectedValue = product.Unit;
txtPrice.Text = product.Price.ToString();
cmbSupplier.SelectedValue = product.Supplier;
cmbManufacturer.SelectedValue = product.Manufacturer;
cmbCategory.SelectedValue = product.ProductCategory;
txtDiscount.Text = product.CurrentDiscount.ToString();
txtStock.Text = product.QuantityInStock.ToString();
txtDescription.Text = product.ProductDescription;
txtPhoto.Text = product.Photo;
originalPhoto = product.Photo;
LoadPhotoPreview(product.Photo);
}
private void btnSelectPhoto_Click(object sender, EventArgs e)
{
using (OpenFileDialog dialog = new OpenFileDialog())
{
// Выбранное фото будет скопировано в Images и приведено к размеру 300x200.
dialog.Title = "Выбор изображения товара";
dialog.Filter = "Изображения|*.jpg;*.jpeg;*.png;*.bmp|Все файлы|*.*";
if (dialog.ShowDialog() != DialogResult.OK)
return;
try
{
using (Image.FromFile(dialog.FileName))
{
}
selectedPhotoPath = dialog.FileName;
txtPhoto.Text = Path.GetFileName(dialog.FileName);
LoadPhotoPreview(selectedPhotoPath);
}
catch (Exception ex)
{
MessageHelper.Warning(
"Выбранный файл не удалось открыть как изображение.\n\n" +
"Выберите файл формата JPG, JPEG, PNG или BMP.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
}
private void btnSave_Click(object sender, EventArgs e)
{
if (!ValidateInput(out Product p))
return;
try
{
p.Photo = SaveSelectedPhotoIfNeeded();
if (isNew)
db.AddProduct(p);
else
db.UpdateProduct(p);
DeleteOldPhotoIfNeeded(p.Photo);
MessageHelper.Info("Данные товара успешно сохранены.");
DialogResult = DialogResult.OK;
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось сохранить товар.\n\n" +
"Проверьте, что артикул уникален, все обязательные поля заполнены, " +
"а база данных доступна.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
private bool ValidateInput(out Product p)
{
p = null;
if (txtArticle.Text.Trim() == "")
{
MessageHelper.Warning(
"Не заполнен артикул товара.\n\n" +
"Введите уникальный артикул товара и повторите сохранение.");
txtArticle.Focus();
return false;
}
if (txtName.Text.Trim() == "")
{
MessageHelper.Warning(
"Не заполнено наименование товара.\n\n" +
"Введите название товара и повторите сохранение.");
txtName.Focus();
return false;
}
if (!double.TryParse(txtPrice.Text, out double price) || price < 0)
{
MessageHelper.Warning(
"Некорректная цена товара.\n\n" +
"Введите положительное число. Например: 2500 или 2500,50.");
txtPrice.Focus();
return false;
}
if (!double.TryParse(txtDiscount.Text, out double discount) || discount < 0 || discount > 100)
{
MessageHelper.Warning(
"Некорректная скидка.\n\n" +
"Введите число от 0 до 100.");
txtDiscount.Focus();
return false;
}
if (!double.TryParse(txtStock.Text, out double stock) || stock < 0)
{
MessageHelper.Warning(
"Некорректное количество товара на складе.\n\n" +
"Введите число 0 или больше.");
txtStock.Focus();
return false;
}
if (cmbUnit.SelectedValue == null ||
cmbSupplier.SelectedValue == null ||
cmbManufacturer.SelectedValue == null ||
cmbCategory.SelectedValue == null)
{
MessageHelper.Warning(
"Не выбраны справочные данные товара.\n\n" +
"Выберите единицу измерения, поставщика, производителя и категорию.");
return false;
}
p = new Product
{
ArticleNumber = txtArticle.Text.Trim(),
ProductName = txtName.Text.Trim(),
Unit = Convert.ToInt32(cmbUnit.SelectedValue),
Price = price,
Supplier = Convert.ToInt32(cmbSupplier.SelectedValue),
Manufacturer = Convert.ToInt32(cmbManufacturer.SelectedValue),
ProductCategory = Convert.ToInt32(cmbCategory.SelectedValue),
CurrentDiscount = discount,
QuantityInStock = stock,
ProductDescription = txtDescription.Text.Trim(),
Photo = txtPhoto.Text.Trim()
};
return true;
}
private string SaveSelectedPhotoIfNeeded()
{
if (string.IsNullOrWhiteSpace(selectedPhotoPath))
return txtPhoto.Text.Trim();
string imagesFolder = Path.Combine(Application.StartupPath, "Images");
Directory.CreateDirectory(imagesFolder);
// Имя файла сохраняем, но убираем символы, запрещенные в именах файлов Windows.
string extension = Path.GetExtension(selectedPhotoPath).ToLower();
if (extension == "")
extension = ".jpg";
string fileName = MakeSafeFileName(Path.GetFileName(selectedPhotoPath));
if (Path.GetExtension(fileName) == "")
fileName += extension;
string destinationPath = Path.Combine(imagesFolder, fileName);
string tempPath = Path.Combine(imagesFolder, Guid.NewGuid().ToString("N") + extension);
using (Image source = Image.FromFile(selectedPhotoPath))
using (Image resized = ResizeImage(source, 300, 200))
{
ImageFormat format = ImageFormat.Jpeg;
if (extension == ".png")
format = ImageFormat.Png;
else if (extension == ".bmp")
format = ImageFormat.Bmp;
resized.Save(tempPath, format);
}
File.Copy(tempPath, destinationPath, true);
File.Delete(tempPath);
return fileName;
}
private Image ResizeImage(Image source, int maxWidth, int maxHeight)
{
Bitmap result = new Bitmap(maxWidth, maxHeight);
// Фото вписывается в 300x200 без искажения пропорций.
using (Graphics graphics = Graphics.FromImage(result))
{
graphics.Clear(Color.White);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
double ratio = Math.Min((double)maxWidth / source.Width, (double)maxHeight / source.Height);
int width = (int)(source.Width * ratio);
int height = (int)(source.Height * ratio);
int x = (maxWidth - width) / 2;
int y = (maxHeight - height) / 2;
graphics.DrawImage(source, x, y, width, height);
}
return result;
}
private void DeleteOldPhotoIfNeeded(string newPhoto)
{
if (isNew || string.IsNullOrWhiteSpace(originalPhoto))
return;
// При замене фото старый файл из Images удаляется, кроме служебных картинок.
if (string.Equals(originalPhoto, newPhoto, StringComparison.OrdinalIgnoreCase))
return;
if (IsDefaultImage(originalPhoto))
return;
string oldPath = Path.Combine(Application.StartupPath, "Images", originalPhoto);
if (File.Exists(oldPath))
File.Delete(oldPath);
}
private bool IsDefaultImage(string photo)
{
return string.Equals(photo, "picture.png", StringComparison.OrdinalIgnoreCase) ||
string.Equals(photo, "Icon.png", StringComparison.OrdinalIgnoreCase);
}
private string MakeSafeFileName(string value)
{
foreach (char c in Path.GetInvalidFileNameChars())
value = value.Replace(c, '_');
return value;
}
private void LoadPhotoPreview(string photo)
{
// Для отсутствующего или поврежденного фото показывается заглушка picture.png.
string imagePath = "";
if (!string.IsNullOrWhiteSpace(photo))
{
if (Path.IsPathRooted(photo) && File.Exists(photo))
imagePath = photo;
else
{
string productPath = Path.Combine(Application.StartupPath, "Images", photo);
if (File.Exists(productPath))
imagePath = productPath;
}
}
string stubPath = Path.Combine(Application.StartupPath, "Images", "picture.png");
if (string.IsNullOrWhiteSpace(imagePath) && File.Exists(stubPath))
imagePath = stubPath;
Image preview = TryLoadImageCopy(imagePath);
if (preview == null && File.Exists(stubPath))
preview = TryLoadImageCopy(stubPath);
if (picPhoto.Image != null)
{
Image oldImage = picPhoto.Image;
picPhoto.Image = null;
oldImage.Dispose();
}
picPhoto.Image = preview;
}
private Image TryLoadImageCopy(string imagePath)
{
if (string.IsNullOrWhiteSpace(imagePath))
return null;
try
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
using (Image temp = Image.FromStream(fs))
{
return new Bitmap(temp);
}
}
catch
{
return null;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
}
📄 ProductsForm.Designer.cs
using System.Drawing;
using System.Windows.Forms;
namespace ToysStore
{
partial class ProductsForm
{
private System.ComponentModel.IContainer components = null;
public Label lblHeader;
public Panel panelTop;
public FlowLayoutPanel panelProducts;
public TextBox txtSearch;
public ComboBox cmbSupplier;
public ComboBox cmbSort;
public Label lblCount;
public Label lblUserInfo;
public PictureBox picLogo;
public Button btnAdd;
public Button btnEdit;
public Button btnDelete;
public Button btnOrders;
public Button btnBack;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.lblHeader = new System.Windows.Forms.Label();
this.panelTop = new System.Windows.Forms.Panel();
this.lblSearch = new System.Windows.Forms.Label();
this.txtSearch = new System.Windows.Forms.TextBox();
this.lblSupplier = new System.Windows.Forms.Label();
this.cmbSupplier = new System.Windows.Forms.ComboBox();
this.lblSort = new System.Windows.Forms.Label();
this.cmbSort = new System.Windows.Forms.ComboBox();
this.lblCount = new System.Windows.Forms.Label();
this.btnAdd = new System.Windows.Forms.Button();
this.btnEdit = new System.Windows.Forms.Button();
this.btnDelete = new System.Windows.Forms.Button();
this.btnOrders = new System.Windows.Forms.Button();
this.btnBack = new System.Windows.Forms.Button();
this.panelProducts = new System.Windows.Forms.FlowLayoutPanel();
this.lblUserInfo = new System.Windows.Forms.Label();
this.picLogo = new System.Windows.Forms.PictureBox();
this.panelTop.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picLogo)).BeginInit();
this.SuspendLayout();
//
// lblHeader
//
this.lblHeader.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.lblHeader.Dock = System.Windows.Forms.DockStyle.Top;
this.lblHeader.Font = new System.Drawing.Font("Times New Roman", 16F, System.Drawing.FontStyle.Bold);
this.lblHeader.Location = new System.Drawing.Point(0, 0);
this.lblHeader.Name = "lblHeader";
this.lblHeader.Padding = new System.Windows.Forms.Padding(64, 0, 0, 0);
this.lblHeader.Size = new System.Drawing.Size(992, 45);
this.lblHeader.TabIndex = 2;
this.lblHeader.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// picLogo
//
this.picLogo.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.picLogo.Location = new System.Drawing.Point(10, 4);
this.picLogo.Name = "picLogo";
this.picLogo.Size = new System.Drawing.Size(40, 37);
this.picLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.picLogo.TabIndex = 4;
this.picLogo.TabStop = false;
this.picLogo.BackColor = ColorTranslator.FromHtml("#F5DEB3");
//
// panelTop
//
this.panelTop.BackColor = System.Drawing.Color.White;
this.panelTop.Controls.Add(this.lblSearch);
this.panelTop.Controls.Add(this.txtSearch);
this.panelTop.Controls.Add(this.lblSupplier);
this.panelTop.Controls.Add(this.cmbSupplier);
this.panelTop.Controls.Add(this.lblSort);
this.panelTop.Controls.Add(this.cmbSort);
this.panelTop.Controls.Add(this.lblCount);
this.panelTop.Controls.Add(this.btnAdd);
this.panelTop.Controls.Add(this.btnEdit);
this.panelTop.Controls.Add(this.btnDelete);
this.panelTop.Controls.Add(this.btnOrders);
this.panelTop.Controls.Add(this.btnBack);
this.panelTop.Dock = System.Windows.Forms.DockStyle.Top;
this.panelTop.Location = new System.Drawing.Point(0, 45);
this.panelTop.Name = "panelTop";
this.panelTop.Size = new System.Drawing.Size(992, 90);
this.panelTop.TabIndex = 1;
//
// lblSearch
//
this.lblSearch.Location = new System.Drawing.Point(10, 15);
this.lblSearch.Name = "lblSearch";
this.lblSearch.Size = new System.Drawing.Size(60, 25);
this.lblSearch.TabIndex = 0;
this.lblSearch.Text = "Поиск:";
//
// txtSearch
//
this.txtSearch.Location = new System.Drawing.Point(70, 12);
this.txtSearch.Name = "txtSearch";
this.txtSearch.Size = new System.Drawing.Size(220, 29);
this.txtSearch.TabIndex = 1;
this.txtSearch.TextChanged += new System.EventHandler(this.FilterChanged);
//
// lblSupplier
//
this.lblSupplier.Location = new System.Drawing.Point(310, 15);
this.lblSupplier.Name = "lblSupplier";
this.lblSupplier.Size = new System.Drawing.Size(90, 25);
this.lblSupplier.TabIndex = 2;
this.lblSupplier.Text = "Поставщик:";
//
// cmbSupplier
//
this.cmbSupplier.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbSupplier.Location = new System.Drawing.Point(400, 12);
this.cmbSupplier.Name = "cmbSupplier";
this.cmbSupplier.Size = new System.Drawing.Size(190, 28);
this.cmbSupplier.TabIndex = 3;
this.cmbSupplier.SelectedIndexChanged += new System.EventHandler(this.FilterChanged);
//
// lblSort
//
this.lblSort.Location = new System.Drawing.Point(610, 15);
this.lblSort.Name = "lblSort";
this.lblSort.Size = new System.Drawing.Size(60, 25);
this.lblSort.TabIndex = 4;
this.lblSort.Text = "Склад:";
//
// cmbSort
//
this.cmbSort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbSort.Items.AddRange(new object[] {
"Без сортировки",
"Количество ↑",
"Количество ↓"});
this.cmbSort.Location = new System.Drawing.Point(670, 12);
this.cmbSort.Name = "cmbSort";
this.cmbSort.Size = new System.Drawing.Size(190, 28);
this.cmbSort.TabIndex = 5;
this.cmbSort.SelectedIndexChanged += new System.EventHandler(this.FilterChanged);
//
// lblCount
//
this.lblCount.Location = new System.Drawing.Point(880, 16);
this.lblCount.Name = "lblCount";
this.lblCount.Size = new System.Drawing.Size(100, 25);
this.lblCount.TabIndex = 6;
//
// btnAdd
//
this.btnAdd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnAdd.Location = new System.Drawing.Point(10, 52);
this.btnAdd.Name = "btnAdd";
this.btnAdd.Size = new System.Drawing.Size(130, 30);
this.btnAdd.TabIndex = 7;
this.btnAdd.Text = "Добавить товар";
this.btnAdd.UseVisualStyleBackColor = false;
this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click);
//
// btnEdit
//
this.btnEdit.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnEdit.Location = new System.Drawing.Point(150, 52);
this.btnEdit.Name = "btnEdit";
this.btnEdit.Size = new System.Drawing.Size(130, 30);
this.btnEdit.TabIndex = 8;
this.btnEdit.Text = "Редактировать";
this.btnEdit.UseVisualStyleBackColor = false;
this.btnEdit.Click += new System.EventHandler(this.btnEdit_Click);
//
// btnDelete
//
this.btnDelete.BackColor = System.Drawing.Color.LightCoral;
this.btnDelete.Location = new System.Drawing.Point(290, 52);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(110, 30);
this.btnDelete.TabIndex = 9;
this.btnDelete.Text = "Удалить";
this.btnDelete.UseVisualStyleBackColor = false;
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// btnOrders
//
this.btnOrders.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(250)))), ((int)(((byte)(154)))));
this.btnOrders.Location = new System.Drawing.Point(410, 52);
this.btnOrders.Name = "btnOrders";
this.btnOrders.Size = new System.Drawing.Size(110, 30);
this.btnOrders.TabIndex = 10;
this.btnOrders.Text = "Заказы";
this.btnOrders.UseVisualStyleBackColor = false;
this.btnOrders.Click += new System.EventHandler(this.btnOrders_Click);
//
// btnBack
//
this.btnBack.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.btnBack.Location = new System.Drawing.Point(857, 52);
this.btnBack.Name = "btnBack";
this.btnBack.Size = new System.Drawing.Size(110, 30);
this.btnBack.TabIndex = 11;
this.btnBack.Text = "Выйти";
this.btnBack.UseVisualStyleBackColor = false;
this.btnBack.Click += new System.EventHandler(this.btnBack_Click);
//
// panelProducts
//
this.panelProducts.AutoScroll = true;
this.panelProducts.BackColor = System.Drawing.Color.White;
this.panelProducts.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelProducts.Location = new System.Drawing.Point(0, 135);
this.panelProducts.Name = "panelProducts";
this.panelProducts.Padding = new System.Windows.Forms.Padding(10);
this.panelProducts.Size = new System.Drawing.Size(992, 615);
this.panelProducts.TabIndex = 0;
//
// lblUserInfo
//
this.lblUserInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.lblUserInfo.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(255)))), ((int)(((byte)(0)))));
this.lblUserInfo.Font = new System.Drawing.Font("Times New Roman", 12F, System.Drawing.FontStyle.Bold);
this.lblUserInfo.Location = new System.Drawing.Point(547, 0);
this.lblUserInfo.Name = "lblUserInfo";
this.lblUserInfo.Size = new System.Drawing.Size(430, 45);
this.lblUserInfo.TabIndex = 3;
this.lblUserInfo.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// ProductsForm
//
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(992, 750);
this.Controls.Add(this.panelProducts);
this.Controls.Add(this.panelTop);
this.Controls.Add(this.lblHeader);
this.Controls.Add(this.lblUserInfo);
this.Controls.Add(this.picLogo);
this.Font = new System.Drawing.Font("Times New Roman", 11F);
this.Name = "ProductsForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ООО Обувь - товары";
((System.ComponentModel.ISupportInitialize)(this.picLogo)).EndInit();
this.panelTop.ResumeLayout(false);
this.panelTop.PerformLayout();
this.ResumeLayout(false);
}
private Label lblSearch;
private Label lblSupplier;
private Label lblSort;
}
}
📄 ProductsForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace ToysStore
{
public partial class ProductsForm : Form
{
private CurrentUser user;
private Db db = new Db();
private List<Product> products = new List<Product>();
private bool isProductEditFormOpen = false;
public ProductsForm(CurrentUser currentUser)
{
user = currentUser;
InitializeComponent();
LoadFormIcon();
LoadBrandAssets();
lblHeader.Text = "Товары";
lblUserInfo.Text = user.FullName + " (" + user.RoleName + ")";
lblUserInfo.BringToFront();
picLogo.BringToFront();
lblUserInfo.BringToFront();
// Права в интерфейсе завязаны на роль: гость, менеджер, администратор.
bool extended = user.Role == UserRole.Manager || user.Role == UserRole.Admin;
txtSearch.Enabled = extended;
cmbSupplier.Enabled = extended;
cmbSort.Enabled = extended;
btnAdd.Visible = user.Role == UserRole.Admin;
btnEdit.Visible = user.Role == UserRole.Admin;
btnDelete.Visible = user.Role == UserRole.Admin;
btnOrders.Visible = user.Role == UserRole.Admin || user.Role == UserRole.Manager;
LoadSuppliers();
LoadProducts();
}
private void LoadBrandAssets()
{
string imagesFolder = Path.Combine(Application.StartupPath, "Images");
string logoPath = Path.Combine(imagesFolder, "Icon.png");
if (File.Exists(logoPath))
{
using (FileStream fs = new FileStream(logoPath, FileMode.Open, FileAccess.Read))
using (Image temp = Image.FromStream(fs))
{
picLogo.Image = new Bitmap(temp);
}
}
}
private void LoadFormIcon()
{
string iconPath = Path.Combine(Application.StartupPath, "Images", "Icon.ico");
if (!File.Exists(iconPath))
return;
try
{
Icon = new Icon(iconPath);
}
catch
{
Icon = null;
}
}
private void LoadSuppliers()
{
cmbSupplier.Items.Clear();
cmbSupplier.Items.Add(new LookupItem { Id = 0, Name = "Все поставщики" });
List<LookupItem> suppliers = db.GetLookup("Suppliers");
foreach (LookupItem supplier in suppliers)
cmbSupplier.Items.Add(supplier);
cmbSupplier.SelectedIndex = 0;
}
private void LoadProducts()
{
try
{
products = db.GetProducts();
RenderProducts();
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось загрузить список товаров.\n\n" +
"Проверьте подключение к базе данных и наличие таблиц Products, Units, Suppliers, Manufacturers, Categories.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
private void FilterChanged(object sender, EventArgs e)
{
if (products == null)
return;
RenderProducts();
}
private void RenderProducts()
{
IEnumerable<Product> query = products;
if (user.Role == UserRole.Manager || user.Role == UserRole.Admin)
{
string search = txtSearch.Text.Trim().ToLower();
if (search.Length > 0)
{
string[] words = search.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
query = query.Where(p =>
{
string allText =
(p.ArticleNumber + " " +
p.ProductName + " " +
p.ProductDescription + " " +
p.Photo + " " +
p.UnitName + " " +
p.SupplierName + " " +
p.ManufacturerName + " " +
p.CategoryName).ToLower();
foreach (string word in words)
{
if (!allText.Contains(word))
return false;
}
return true;
});
}
LookupItem selectedSupplier = cmbSupplier.SelectedItem as LookupItem;
if (selectedSupplier != null && selectedSupplier.Id != 0)
{
query = query.Where(p => p.Supplier == selectedSupplier.Id);
}
if (cmbSort.SelectedIndex == 1)
query = query.OrderBy(p => p.QuantityInStock);
if (cmbSort.SelectedIndex == 2)
query = query.OrderByDescending(p => p.QuantityInStock);
}
List<Product> result = query.ToList();
lblCount.Text = result.Count + " из " + products.Count;
panelProducts.Controls.Clear();
panelProducts.Tag = null;
foreach (Product p in result)
panelProducts.Controls.Add(CreateCard(p));
}
private Panel CreateCard(Product p)
{
Color cardColor = GetCardColor(p);
// Разметка карточки повторяет макет задания: фото, данные товара, блок скидки.
Panel card = new Panel();
card.Width = 900;
card.Height = 185;
card.Margin = new Padding(10);
card.BorderStyle = BorderStyle.FixedSingle;
card.Tag = p;
card.BackColor = cardColor;
Panel photoBlock = new Panel();
photoBlock.Location = new Point(18, 12);
photoBlock.Size = new Size(245, 160);
photoBlock.BorderStyle = BorderStyle.FixedSingle;
photoBlock.BackColor = cardColor;
photoBlock.Tag = p;
PictureBox pic = new PictureBox();
pic.Location = new Point(18, 18);
pic.Size = new Size(210, 124);
pic.SizeMode = PictureBoxSizeMode.Zoom;
pic.Image = LoadProductImage(p.Photo);
pic.Tag = p;
Label photoText = new Label();
photoText.Text = "Фото";
photoText.Location = new Point(88, 65);
photoText.Size = new Size(70, 30);
photoText.TextAlign = ContentAlignment.MiddleCenter;
photoText.BorderStyle = BorderStyle.FixedSingle;
photoText.BackColor = Color.White;
photoText.Visible = pic.Image == null;
photoText.Tag = p;
photoBlock.Controls.Add(pic);
photoBlock.Controls.Add(photoText);
Panel infoBlock = new Panel();
infoBlock.Location = new Point(272, 12);
infoBlock.Size = new Size(465, 160);
infoBlock.BorderStyle = BorderStyle.FixedSingle;
infoBlock.BackColor = cardColor;
infoBlock.Tag = p;
Label lblTitle = new Label();
lblTitle.Location = new Point(10, 8);
lblTitle.Size = new Size(445, 23);
lblTitle.Font = new Font("Times New Roman", 11F, FontStyle.Bold);
lblTitle.Text = p.CategoryName + " | " + p.ProductName;
lblTitle.AutoEllipsis = true;
lblTitle.Tag = p;
Label lblDescription = CreateInfoLabel("Описание товара: " + p.ProductDescription, 10, 31, 445, 22, p);
Label lblManufacturer = CreateInfoLabel("Производитель: " + p.ManufacturerName, 10, 53, 445, 22, p);
Label lblSupplier = CreateInfoLabel("Поставщик: " + p.SupplierName, 10, 75, 445, 22, p);
Label lblUnit = CreateInfoLabel("Единица измерения: " + p.UnitName, 10, 119, 260, 22, p);
Label lblStock = CreateInfoLabel("Количество на складе: " + p.QuantityInStock.ToString("N0"), 10, 140, 330, 22, p);
infoBlock.Controls.Add(lblTitle);
infoBlock.Controls.Add(lblDescription);
infoBlock.Controls.Add(lblManufacturer);
infoBlock.Controls.Add(lblSupplier);
AddPriceLabels(infoBlock, card, p);
infoBlock.Controls.Add(lblUnit);
infoBlock.Controls.Add(lblStock);
Panel discountBlock = new Panel();
discountBlock.Location = new Point(746, 12);
discountBlock.Size = new Size(135, 160);
discountBlock.BorderStyle = BorderStyle.FixedSingle;
discountBlock.BackColor = cardColor;
discountBlock.Tag = p;
Label lblDiscount = new Label();
lblDiscount.Location = new Point(8, 45);
lblDiscount.Size = new Size(118, 60);
lblDiscount.Font = new Font("Times New Roman", 10F, FontStyle.Bold);
lblDiscount.Text = "Действующая\nскидка\n" + p.CurrentDiscount.ToString("N0") + "%";
lblDiscount.TextAlign = ContentAlignment.MiddleCenter;
lblDiscount.Tag = p;
discountBlock.Controls.Add(lblDiscount);
card.Controls.Add(photoBlock);
card.Controls.Add(infoBlock);
card.Controls.Add(discountBlock);
AddCardEvents(card, card);
AddCardEvents(photoBlock, card);
AddCardEvents(infoBlock, card);
AddCardEvents(discountBlock, card);
AddCardEvents(pic, card);
AddCardEvents(photoText, card);
AddCardEvents(lblTitle, card);
AddCardEvents(lblDescription, card);
AddCardEvents(lblSupplier, card);
AddCardEvents(lblManufacturer, card);
AddCardEvents(lblUnit, card);
AddCardEvents(lblStock, card);
AddCardEvents(lblDiscount, card);
return card;
}
private Label CreateInfoLabel(string text, int x, int y, int width, int height, Product product)
{
Label label = new Label();
label.Text = text;
label.Location = new Point(x, y);
label.Size = new Size(width, height);
label.AutoEllipsis = true;
label.Tag = product;
return label;
}
private void AddPriceLabels(Panel infoBlock, Panel card, Product p)
{
if (p.CurrentDiscount > 0)
{
double finalPrice = p.Price * (1 - p.CurrentDiscount / 100.0);
Label priceTitle = CreateInfoLabel("Цена:", 10, 97, 50, 22, p);
Label oldPrice = new Label();
oldPrice.Location = new Point(60, 97);
oldPrice.Size = new Size(120, 22);
oldPrice.Text = p.Price.ToString("N2") + " руб.";
oldPrice.ForeColor = Color.Red;
oldPrice.Font = new Font("Times New Roman", 11F, FontStyle.Strikeout);
oldPrice.Tag = p;
Label newPrice = new Label();
newPrice.Location = new Point(185, 97);
newPrice.Size = new Size(210, 22);
newPrice.Text = finalPrice.ToString("N2") + " руб.";
newPrice.ForeColor = Color.Black;
newPrice.Font = new Font("Times New Roman", 11F, FontStyle.Bold);
newPrice.Tag = p;
infoBlock.Controls.Add(priceTitle);
infoBlock.Controls.Add(oldPrice);
infoBlock.Controls.Add(newPrice);
AddCardEvents(priceTitle, card);
AddCardEvents(oldPrice, card);
AddCardEvents(newPrice, card);
}
else
{
Label price = CreateInfoLabel("", 10, 97, 250, 22, p);
price.Text = "Цена: " + p.Price.ToString("N2") + " руб.";
price.ForeColor = Color.Black;
infoBlock.Controls.Add(price);
AddCardEvents(price, card);
}
}
private void AddCardEvents(Control control, Panel card)
{
control.Click += delegate
{
SelectCard(card);
};
control.DoubleClick += delegate
{
SelectCard(card);
if (user.Role == UserRole.Admin)
OpenEditForm(card.Tag as Product);
};
}
private Color GetCardColor(Product p)
{
if (p.QuantityInStock <= 0)
return Color.LightBlue;
if (p.CurrentDiscount > 15)
return ColorTranslator.FromHtml("#2E8B57");
return Color.White;
}
private Image LoadProductImage(string fileName)
{
string imagesFolder = Path.Combine(Application.StartupPath, "Images");
string stubPath = Path.Combine(imagesFolder, "picture.png");
// Если фото товара отсутствует или повреждено, показывается Images\picture.png.
string imagePath = "";
if (!string.IsNullOrWhiteSpace(fileName))
{
string productPath = Path.Combine(imagesFolder, fileName);
if (File.Exists(productPath))
imagePath = productPath;
}
if (string.IsNullOrWhiteSpace(imagePath) && File.Exists(stubPath))
imagePath = stubPath;
if (string.IsNullOrWhiteSpace(imagePath))
return null;
Image image = TryLoadImageCopy(imagePath);
if (image != null)
return image;
if (!string.Equals(imagePath, stubPath, StringComparison.OrdinalIgnoreCase) && File.Exists(stubPath))
return TryLoadImageCopy(stubPath);
return null;
}
private Image TryLoadImageCopy(string imagePath)
{
try
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
using (Image temp = Image.FromStream(fs))
{
return new Bitmap(temp);
}
}
catch
{
return null;
}
}
private void SelectCard(Panel selectedCard)
{
foreach (Control item in panelProducts.Controls)
{
Product product = item.Tag as Product;
RestoreCardColor(item, GetCardColor(product));
}
RestoreCardColor(selectedCard, ColorTranslator.FromHtml("#00FA9A"));
panelProducts.Tag = selectedCard.Tag;
}
private void RestoreCardColor(Control control, Color color)
{
control.BackColor = color;
foreach (Control child in control.Controls)
{
if (child is PictureBox || child is Button)
continue;
Label label = child as Label;
if (label != null && label.BorderStyle == BorderStyle.FixedSingle)
child.BackColor = Color.White;
else
RestoreCardColor(child, color);
}
}
private Product SelectedProduct()
{
return panelProducts.Tag as Product;
}
private void OpenEditForm(Product product)
{
if (product == null)
return;
// Администратор не должен открыть несколько окон редактирования товара одновременно.
if (isProductEditFormOpen)
{
MessageHelper.Warning(
"Окно редактирования товара уже открыто.\n\n" +
"Завершите добавление или редактирование текущего товара, затем откройте следующий.");
return;
}
isProductEditFormOpen = true;
try
{
ProductEditForm form = new ProductEditForm(product);
if (form.ShowDialog() == DialogResult.OK)
LoadProducts();
}
finally
{
isProductEditFormOpen = false;
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
if (isProductEditFormOpen)
{
MessageHelper.Warning(
"Окно редактирования товара уже открыто.\n\n" +
"Завершите добавление или редактирование текущего товара, затем откройте следующий.");
return;
}
isProductEditFormOpen = true;
try
{
ProductEditForm form = new ProductEditForm(null);
if (form.ShowDialog() == DialogResult.OK)
LoadProducts();
}
finally
{
isProductEditFormOpen = false;
}
}
private void btnEdit_Click(object sender, EventArgs e)
{
Product p = SelectedProduct();
if (p == null)
{
MessageHelper.Warning(
"Товар не выбран.\n\n" +
"Сначала нажмите на карточку товара, затем повторите действие.");
return;
}
OpenEditForm(p);
}
private void btnDelete_Click(object sender, EventArgs e)
{
Product p = SelectedProduct();
if (p == null)
{
MessageHelper.Warning(
"Товар не выбран.\n\n" +
"Сначала нажмите на карточку товара, затем повторите действие.");
return;
}
if (MessageHelper.Confirm(
"Вы действительно хотите удалить выбранный товар?\n\n" +
"Это действие нельзя отменить. Если товар используется в заказах, удаление будет запрещено."))
{
try
{
db.DeleteProduct(p.ArticleNumber);
MessageHelper.Info("Товар успешно удален.");
LoadProducts();
}
catch (Exception ex)
{
MessageHelper.Error(
"Не удалось удалить товар.\n\n" +
"Возможная причина: товар используется в заказах. Удалите связанные записи заказа или оставьте товар в базе.\n\n" +
"Техническая информация:\n" + ex.Message);
}
}
}
private void btnOrders_Click(object sender, EventArgs e)
{
OrdersForm form = new OrdersForm(user);
form.ShowDialog();
}
private void btnBack_Click(object sender, EventArgs e)
{
Close();
}
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net6.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 230 | 12/4/2025 |