Кирилл Яковлев 61e6ab4e7b first commit 1 сар өмнө
..
build 61e6ab4e7b first commit 1 сар өмнө
lib 61e6ab4e7b first commit 1 сар өмнө
.signature.p7s 61e6ab4e7b first commit 1 сар өмнө
AlfaToad.CustomControls.4.2.9.nupkg 61e6ab4e7b first commit 1 сар өмнө
README.md 61e6ab4e7b first commit 1 сар өмнө

README.md

AlfaToad.CustomControls

Библиотека пользовательских контролов для Windows Forms (.NET Framework 4.8 и .NET 8).

Пакет: NuGet — AlfaToad.CustomControls

Компоненты

Контрол Назначение
ScrollableDetailPanel Прокручиваемый список строк с фото, полями товара и скидкой
ScrollableOrderPanel Прокручиваемый список строк заказа
BoundDataGridView Таблица с привязкой к DataSet и подсветкой столбца

Установка

dotnet add package AlfaToad.CustomControls --version 4.2.1
<PackageReference Include="AlfaToad.CustomControls" Version="4.2.1" />

ScrollableDetailPanel — настраиваемые свойства

Поля данных (имена столбцов в DataTable)

Поле на экране Свойство Значение по умолчанию
Фото ImageField Фото
Категория CategoryField Категория товара
Наименование NameField Наименование товара
Описание DescriptionField Описание товара
Производитель ManufacturerField Производитель
Поставщик SupplierField Поставщик
Цена PriceField Цена
Единица измерения UnitField Единица измерения
Количество на складе StockField Кол-во на складе
Скидка DiscountField Действующая скидка

Подписи на экране

Подпись Свойство Значение по умолчанию
Описание DescriptionCaption Описание товара:
Производитель ManufacturerCaption Производитель:
Поставщик SupplierCaption Поставщик:
Цена PriceCaption Цена:
Единица измерения UnitCaption Единица измерения:
Количество на складе StockCaption Количество на складе:
Заголовок столбца скидки DiscountCaption Действующая скидка

Изображения

Свойство Описание
NoImage Картинка при отсутствии файла или пустом поле. По умолчанию не задана — область фото остаётся пустой.
ImagesFolder Папка, из которой загружаются файлы по имени из ImageField.

Размеры строки

Свойство По умолчанию
RowHeight 160
ImageColumnWidth 120
DiscountColumnWidth 110
RowSpacing 8 (зона сепаратора между строками)
OutOfStockRowColor голубой #ADD8E6 (количество на складе ≤ 0)
RowSeparatorColor Silver (линия между записями)
ImageLeftPadding 8 (отступ фото от левого края)
DataSource источник данных в дизайнере (DataSet / DataTable / BindingSource)
DataMember имя таблицы в DataSet

ScrollableOrderPanel — настраиваемые свойства

Поля данных

Поле на экране Свойство Значение по умолчанию
Артикул заказа ArticleField Артикул заказа
Статус StatusField Статус заказа
Адрес пункта выдачи AddressField Адрес пункта выдачи
Дата заказа OrderDateField Дата заказа
Дата доставки DeliveryDateField Дата доставки

Подписи на экране

Подпись Свойство Значение по умолчанию
Артикул ArticleCaption Артикул заказа
Статус StatusCaption Статус заказа
Адрес AddressCaption Адрес пункта выдачи
Дата заказа OrderDateCaption Дата заказа
Дата доставки DeliveryDateCaption Дата доставки

Размеры строки

Свойство По умолчанию
RowHeight 110
DeliveryColumnWidth 140

Добавление, редактирование и удаление (CRUD)

Оба списка (ScrollableDetailPanel, ScrollableOrderPanel) поддерживают кнопки Добавить / Изменить / Удалить и клик по строке для редактирования. Формы добавления и редактирования открывает ваше приложение в обработчиках событий.

Права по ролям

Свойство Описание По умолчанию
AllowAdd Показать кнопку добавления false
AllowEdit Показать кнопку изменения и открывать редактирование по клику на строку false
AllowDelete Показать кнопку удаления false
IsEditSessionActive Блокирует второе окно редактирования, пока true false
ValidateBeforeDelete Функция проверки перед удалением; верните текст ошибки для запрета null

При false соответствующая кнопка скрывается. При попытке действия без прав показывается MessageBox с пояснением.

События

Событие Когда срабатывает
RecordAddRequested Нажата кнопка «Добавить»
RecordEditRequested Клик по строке или кнопка «Изменить»
RecordDeleting Перед удалением; установите Cancel = true и DenyReason для отмены
RecordDeleted Строка удалена из DataTable (вызовите Update в БД)

После закрытия формы редактирования вызовите EndEditSession(), чтобы снова можно было открыть другое окно.

Пример для администратора (товары)

var panel = new ScrollableDetailPanel { Dock = DockStyle.Fill };
panel.AllowAdd = panel.AllowEdit = panel.AllowDelete = userIsAdmin;
panel.ShowQueryPanel = userIsManagerOrAdmin;

panel.ValidateBeforeDelete = row =>
{
    var article = row["Артикул"]?.ToString();
    return ProductExistsInOrders(article)
        ? "Товар присутствует в заказе и не может быть удалён."
        : null;
};

panel.RecordAddRequested += (_, __) => OpenProductForm(null);
panel.RecordEditRequested += (_, e) => OpenProductForm(e.Row);
panel.RecordDeleted += (_, e) =>
{
    tableAdapter.Update(dataSet);
    panel.RefreshRows();
};

Пример для менеджера (заказы — только просмотр)

ordersPanel.AllowAdd = ordersPanel.AllowEdit = ordersPanel.AllowDelete = userIsAdmin;
// менеджер: все три свойства false — кнопки скрыты, клик только выделяет строку

Обработка исключительных случаев

Библиотека показывает MessageBox в ситуациях:

  • действие недоступно для роли;
  • не выбрана запись для изменения или удаления;
  • уже открыто окно редактирования (IsEditSessionActive);
  • ValidateBeforeDelete или RecordDeleting запретили удаление;
  • ошибка при удалении строки из DataTable.

BoundDataGridView — настраиваемые свойства

Свойство Описание По умолчанию
HighlightColumnName Столбец для подсветки ячеек Действующая скидка
ApplyRowHighlight Включить подсветку true
Appearance Палитра цветов см. ниже

AppearancePalette — настройка цветов и шрифтов

Общий объект Appearance доступен у всех трёх контролов.

Редактор в дизайнере Visual Studio

  1. Выберите контрол на форме.
  2. В окне Свойства найдите Appearance.
  3. Разверните узел — каждый цвет редактируется стандартным выбором цвета.
  4. Нажмите «…» рядом с Appearance — откроется окно «Палитра оформления» со всеми цветами, шрифтами и порогом скидки; кнопка «По умолчанию» сбрасывает значения.

Изменения сразу применяются к контролу на форме в режиме дизайна.

Свойство Назначение По умолчанию
MainBackground Основной фон #FFFFFF
SectionBackground Фон заголовков таблицы #F5DEB3
AccentBackground Линии сетки таблицы #DEB887
HighlightBackground Подсветка скидки > порога #FFDEAD
SelectedRowBackground Фон выбранной строки списка #E8EEF8
PrimaryText Цвет текста Black
SeparatorText Цвет разделителя \| Gray
BorderColor Рамки строк списка Black
RowSeparatorColor Линия между записями Silver
OutOfStockBackground Фон строки без товара на складе #ADD8E6
StrikethroughPriceColor Перечёркнутая цена при скидке Red
FinalPriceColor Итоговая цена при скидке Black
FontFamily Шрифт Arial
BaseFontSize Размер обычного текста 9
TitleFontSize Размер заголовка строки 10
HighlightThresholdPercent Порог подсветки скидки (%) 17

Алгоритм расчёта скидки

Назначение

Вычисление итоговой цены товара с учётом действующей скидки и определение способа отображения цены на экране (ScrollableDetailPanel, BoundDataGridView).

Входные данные

Обозначение Описание Источник
Ц Исходная цена товара столбец Цена (PriceField)
С Действующая скидка, % столбец Действующая скидка (DiscountField)
П Порог подсветки скидки, % Appearance.HighlightThresholdPercent (по умолчанию 17)

Выходные данные

Обозначение Описание
Ц_итог Итоговая цена (руб., 2 знака после запятой)
Режим Способ отображения: «только цена» или «перечёркнутая + итоговая»
Подсветка Применять ли фон подсветки для ячейки/блока скидки

Формула

Если Ц > 0 и С > 0:

Ц_итог = ОКРУГЛ( Ц × (1 − С / 100) ; 2 )

Иначе:

Ц_итог = Ц

Округление — математическое, до 2 знаков (MidpointRounding.AwayFromZero).

Обозначения блок-схемы (ГОСТ 19.701-90)

Символ Наименование по ГОСТ Назначение в схеме
◯ (овал) Терминатор Начало / конец алгоритма
▱ (параллелограмм) Данные Ввод исходных значений Ц, С, П
▭ (прямоугольник) Процесс Вычисление, присваивание, форматирование
◇ (ромб) Решение Проверка условия (да / нет)

Блок-схема алгоритма (ГОСТ 19.701-90)

В диаграмме Mermaid: овал — терминатор, параллелограмм — ввод/вывод, прямоугольник — процесс, ромб — решение.

flowchart TD
    A([НАЧАЛО]) --> B[/Ввод: Ц — цена, С — скидка %, П — порог подсветки/]
    B --> C{Ц ≤ 0<br/>ИЛИ<br/>С ≤ 0?}
    C -- ДА --> D[Ц_итог := Ц]
    C -- НЕТ --> E[Ц_итог := ОКРУГЛ Ц × 1 − С / 100 ; 2]
    D --> F{С > 0<br/>И<br/>Ц > 0?}
    E --> F
    F -- ДА --> G[Режим := перечёркнутая Ц + итоговая Ц_итог]
    F -- НЕТ --> H[Режим := отображать только Ц]
    G --> I{С > П?}
    H --> I
    I -- ДА --> J[Подсветка := включить HighlightBackground]
    I -- НЕТ --> K[Подсветка := обычный фон]
    J --> L[/Вывод: Ц_итог, Режим, Подсветка/]
    K --> L
    L --> M([КОНЕЦ])

Блок-схема в текстовом виде (ГОСТ 19.701-90)

        ┌─────────────────────────────────┐
        │            НАЧАЛО               │  ← терминатор (овал)
        └───────────────┬─────────────────┘
                        ▼
        ╔═════════════════════════════════╗
        ║  Ввод: Ц, С, П                  ║  ← данные (параллелограмм)
        ╚═════════════════════════════════╝
                        ▼
                ┌───────────────┐
                │  Ц ≤ 0  ИЛИ   │
                │  С ≤ 0 ?      │              ← решение (ромб)
                └───┬───────┬───┘
               ДА   │       │   НЕТ
                    ▼       ▼
        ┌───────────────┐   ┌───────────────────────────────┐
        │ Ц_итог := Ц   │   │ Ц_итог := ОКРУГЛ(Ц×(1−С/100);2)│  ← процесс
        └───────┬───────┘   └───────────────┬───────────────┘
                └───────────┬───────────────┘
                            ▼
                    ┌───────────────┐
                    │ С > 0  И      │
                    │ Ц > 0 ?       │              ← решение (ромб)
                    └───┬───────┬───┘
                   ДА   │       │   НЕТ
                        ▼       ▼
        ┌───────────────────────┐   ┌─────────────────────────┐
        │ Режим := перечёркнутая│   │ Режим := только Ц       │
        │ цена + Ц_итог         │   └───────────┬─────────────┘
        └───────────┬───────────┘               │
                    └───────────┬───────────────┘
                                ▼
                        ┌───────────────┐
                        │   С > П ?     │          ← решение (ромб)
                        └───┬───────┬───┘
                       ДА   │       │   НЕТ
                            ▼       ▼
        ┌───────────────────────┐   ┌─────────────────────────┐
        │ Подсветка := ДА       │   │ Подсветка := НЕТ        │
        └───────────┬───────────┘   └───────────┬─────────────┘
                    └───────────┬───────────────┘
                                ▼
        ╔═════════════════════════════════╗
        ║  Вывод: Ц_итог, Режим,          ║  ← данные (параллелограмм)
        ║         Подсветка               ║
        ╚═════════════════════════════════╝
                                ▼
        ┌─────────────────────────────────┐
        │             КОНЕЦ                │  ← терминатор (овал)
        └─────────────────────────────────┘

Таблица решений (ветвления)

Условие Действие
1 Ц ≤ 0 или С ≤ 0 Ц_итог = Ц (скидка не применяется)
2 Ц > 0 и С > 0 Ц_итог = ОКРУГЛ(Ц × (1 − С/100); 2)
3 С > 0 и Ц > 0 Показать старую цену красной перечёркнутой и рядом итоговую чёрную
4 иначе Показать только Ц
5 С > П Подсветить ячейку/блок скидки цветом HighlightBackground
6 С ≤ П Обычный фон

Примеры расчёта

Ц, руб. С, % Ц_итог, руб. Отображение
1000 0 1000,00 1000,00
1000 15 850,00 1000,00 850,00
1000 20 800,00 1000,00 800,00 + подсветка (20 > 17)
0 10 0,00 0,00 (скидка не считается)
500 −5 500,00 500,00 (отрицательная скидка игнорируется)

Соответствие коду библиотеки

Шаг алгоритма Реализация
Расчёт Ц_итог ScrollableDetailPanel.CalculateFinalPrice
Отображение цены в строке ProductListRowPriceLinePanel
Подсветка скидки в списке Appearance.HighlightThresholdPercent
Подсветка в таблице BoundDataGridView.OnCellFormatting

Примеры использования

Список товаров с привязкой к DataSet

using System.Data;
using System.Drawing;
using AlfaToad.CustomControls.Controls;
using AlfaToad.CustomControls.Theme;

var panel = new ScrollableDetailPanel { Dock = DockStyle.Fill };

panel.NoImage = Image.FromFile(@"C:\images\no-photo.png");
panel.ImagesFolder = @"C:\images\products";

panel.CategoryField = "CategoryName";
panel.NameField = "ProductName";
panel.DiscountField = "DiscountPercent";

panel.Appearance = new AppearancePalette
{
    MainBackground = Color.White,
    HighlightBackground = Color.FromArgb(255, 222, 173),
    BorderColor = Color.Black,
    HighlightThresholdPercent = 17m
};

DataSet dataSet = LoadProducts();
panel.BindDataSet(dataSet, "Products");

Поведение цены: если Действующая скидка > 0, основная цена отображается красной и перечёркнутой, рядом — итоговая цена чёрным (цена × (1 − скидка/100)).

Нет на складе: если Кол-во на складе ≤ 0, вся строка подсвечивается цветом OutOfStockRowColor.

Поиск, фильтрация и сортировка (ScrollableDetailPanel)

Панель включена по умолчанию (ShowQueryPanel = true). Всё применяется в реальном времени без кнопки «Найти».

Элемент Поведение
Поиск Подстрока по всем текстовым столбцам (string), одновременно по нескольким полям (логика OR)
Сортировка Цена ↑/↓, кол-во на складе ↑/↓; выбор сохраняется при поиске и фильтре
Поставщик Выпадающий список; первый пункт Все поставщики сбрасывает фильтр
Свойство Описание
ShowQueryPanel Показать панель (по умолчанию true)
AllSuppliersCaption Текст сброса фильтра (Все поставщики)
SearchFields Ограничить столбцы поиска (пусто = все текстовые)
SupplierField Столбец для фильтра поставщика (Поставщик)
PriceField / StockField Столбцы для сортировки
panel.ShowQueryPanel = userIsManagerOrAdmin;

После TableAdapter.Fill(...) список и список поставщиков обновляются автоматически.

Список заказов

var orders = new ScrollableOrderPanel { Dock = DockStyle.Fill };
orders.Appearance = AppearancePalette.CreateDefault();
orders.Appearance.AccentBackground = Color.BurlyWood;
orders.BindDataSet(dataSet, "Orders");

Таблица с подсветкой скидки

var grid = new BoundDataGridView { Dock = DockStyle.Fill };
grid.Appearance = AppearancePalette.CreateDefault();
grid.HighlightColumnName = "Действующая скидка";
grid.ApplyDefaultStyle();
grid.BindDataSet(dataSet, "Products");

Смена цветов после создания

panel.Appearance.MainBackground = ColorTranslator.FromHtml("#FAFAFA");
panel.Appearance.HighlightBackground = ColorTranslator.FromHtml("#FFDEAD");
panel.Appearance.BorderColor = Color.DimGray;
panel.ApplyAppearance();