| Предыдущая лекция | Следующая лекция | |
|---|---|---|
| Пагинация, сортировка, фильтрация, поиск | Содержание | Создание, изменение продукции |
В списке продукции необходимо подсвечивать светло-красным цветом те продукты, которые не продавались агентами в последний месяц.
| Критерий | Баллы |
|---|---|
| Реализовано выделение (любым образом) продуктов, которые не продавались агентами в последний месяц | 1.5 |
| Выделение реализовано в виде светло-красной подсветки элемента продукции | 0.5 |
| Итого | 2 |
В самом списке продукции данных о продажах нет. Судя по названиям таблиц данные эти должны быть в таблице ProductSale. Судя по связям этой таблицы, мы должны заполнить ещё таблицы Agent и AgentType.
На демо-экзамене до этого вы вряд-ли дойдёте (хотя критерий достаточно жирный), но в рамках курсовой/дипломной работы реализовать дополнительный функционал надо.
Добавляем типы агентов
Исходных данных для этой и последующих таблиц нет, поэтому вы можете писать туда что угодно (но близко к предметной области). Для типов агентов подойдут "индивидуальный предприниматель" и "Общество с ограниченной ответственностью" (для не обязательных таблиц много данных придумывать не надо, достаточно одной-двух записей)
И так как исходных данных нет, то добавляем данные прямо в таблицы.
Добавляем агента
Тут заполняем только обязательные поля. AgentTypeID смотрим в таблице AgentType.
Создание продаж продукции
Добавляем несколько записей в таблицу ProductSale. Поля AgentID и ProductID смотрим в соответствующих таблицах. Дата продажи заполняется в формате YYYY-MM-DD
Для получения количества продаж за последний месяц пишем SQL запрос:
SELECT
ProductID, count(*) as qty
FROM
ProductSale ps
WHERE
ps.SaleDate > DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY
ProductID;
Функция DATE_SUB вычитает из указанной даты (NOW - сейчас) нужное количество месяцев (можно в интервале указать дни, минуты и т.д.)
И добаляем этот подзапрос в наш ProductView:
CREATE VIEW ProductView AS
SELECT
-- выбираю все поля из Product
p.*,
pt.TitleType AS ProductTypeTitle,
qq.MaterialCost,
qq.MaterialString,
-- добавляю поле "количество продаж за последний месяц"
ps.LastMonthSaleQuantity
FROM
Product p
LEFT JOIN
ProductType pt ON p.ProductTypeID = pt.ID
LEFT JOIN
(
SELECT
pm.ProductID,
SUM(pm.`Count` * m.Cost) AS MaterialCost,
GROUP_CONCAT(m.Title, ',') AS MaterialString
FROM
ProductMaterial pm,
Material m
WHERE
pm.MaterialID=m.ID
GROUP BY
pm.ProductID
) qq ON qq.ProductID=p.ID
-- добавляю подзапрос для выборки количества продаж за последний месяц
LEFT JOIN
(
SELECT
ProductID,
count(*) as LastMonthSaleQuantity
FROM
ProductSale
WHERE
SaleDate > DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY
ProductID
) ps ON ps.ProductID=p.ID;
Тут элементарно. У элемента рамка (Border) задаем цвет фона:
<Border
BorderThickness="1"
BorderBrush="Black"
Background="{Binding BackgroundColor}"
^^^^^^^^^^^^^^^^^^^^^^^^^
CornerRadius="5">
И добавляем в модель Product геттер BackgroundColor
public int? LastMonthSaleQuantity { get; set; }
public string BackgroundColor
{
get
{
// возвращаем цвет, в зависимости от количества продаж
if (LastMonthSaleQuantity == null || LastMonthSaleQuantity == 0) return "#fee"; // белый
return "#fff"; // розовый
}
}
Про цвета: их можно отдавать в формате #RGB. Причём, чем ближе к F, тем светлее (#FFF - белый)
Необходимо добавить возможность изменения минимальной стоимости продукции для агента сразу для нескольких выбранных продуктов. Для этой цели реализуйте возможность выделения сразу нескольких элементов в списке продукции, после чего должна появиться кнопка “Изменить стоимость на ...”. При нажатии на кнопку необходимо отобразить модальное окно с возможностью ввода числового значения, на которое и будет увеличена стоимость выбранных продуктов. По умолчанию в поле должно быть введено среднее значение цены на продукцию для агента. После нажатия кнопки “Изменить” стоимость выделенных продуктов должна быть изменена в базе данных, а также обновлена в интерфейсе.
| Критерий | Баллы |
|---|---|
| Реализована возможность выделения сразу нескольких элементов в списке | 0.2 |
| После выделения элементов в списке появляется кнопка "Изменить стоимость на ..." | 0.3 |
| При нажатии на кнопку отображается модальное окно для изменения цены | 0.1 |
| В модальном окне есть возможность ввода числового значения | 0.1 |
| По умолчанию введено значение средней цены выбранных продуктов | 0.2 |
| Реализована проверка на ввод только числового значения | 0.2 |
| После нажатия кнопки "Изменить" стоимость всех выбранных продуктов изменяется в БД | 0.5 |
| После нажатия кнопки "Изменить" стоимость всех выбранных продуктов обновляется в списке | 0.2 |
| Итого | 1.8 |
Возможность выделения нескольких элементов в ListBox есть, нужно только добавить аттрибут SelectionMode="Multiple". Реализовать событие выбора и сосчитать количество выделенных элементов.
В ListBox нужно добавить название (мы потом будем по нему искать количество выделенных элементов) и обработчик события SelectionChanged
Name="ProductListBox"
SelectionMode="Multiple"
SelectionChanged="ProductListBox_OnSelectionChanged"
Реализуем обработчик ProductListBox_OnSelectionChanged:
public int productsSelectedCount = 0;
private void ProductListBox_OnSelectionChanged(
object? sender,
SelectionChangedEventArgs e)
{
if (ProductListBox != null)
{
productsSelectedCount = ProductListBox. SelectedItems.Count;
}
}
Сначала просто добавляем эту кнопку в разметку (можно в панель управления, можно в левую панель) и, чтобы видимость кнопки зависела от количества выделенных элементов, мы привязываем атрибут Visibility к свойству costChangeButtonVisible
<Button
x:Name="CostChangeButton"
Visibility="{Binding costChangeButtonVisible}" Content="Изменить стоимость на..."
/>
И реализуем это свойство в коде ОКНА
public string costChangeButtonVisible
{
get
{
return productsSelectedCount > 1 ? "Visible" : "Hidden";
}
}
Осталось в обработчик события ProductListBox_OnSelectionChanged вставить вызов метода Invalidate для свойства costChangeButtonVisible
Добавляем кнопке обработчик события клика
<Button
x:Name="CostChangeButton"
Visibility="{Binding costChangeButtonVisible}"
Content="Изменить стоимость на..."
Click="CostChangeButton_Click"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/>
Создаем и показываем модальное окно
Вспоминаем, что мы должны соблюдать файловую структуру проекта, т.е. все однотипные объекты распихивать по соответствующим папкам.
Создадим папку Windows и в неё добавим окно:
Название окна должно быть осмысленным и с суффиксом Window. У меня получилось EnterMinCostForAgentWindow
Можно в каталог
Windowsперетащить и главное окно MainWindow.
Опять же, все окна должны иметь нормальные заголовки. В разметке окна поменяйте атрибут Title элемента Window (это надо сделать и для основного окна)
Содержимое у этого окна элементарное (текстовое поле и кнопка):
<StackPanel
Orientation="Vertical" Margin="0,50,0,0">
<TextBox
Name="CostTextBox"
/>
<Button
Content="Изменить"/>
</StackPanel>
В коде этого окна меняем конструктор:
public EnterMinCostForAgentWindow(decimal AvgCost)
^^^^^^^^^^^^^^^
{
InitializeComponent();
CostTextBox.Text = AvgCost.ToString();
}
Во-первых, в конструктор добавляем параметр (средняя цена). Во-вторых, записываем эту цену в текстовое поле.
И пишем обработчик клика на кнопку "Изменить":
// объявляем публичную переменную из которой
// будем считывать результат
public decimal Result;
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
// пробуем сконвертировать в число
Result = Convert.ToDecimal(CostTextBox.Text);
// при присвоении результата свойству DialogResult модальное окно закрывается
DialogResult = true;
}
catch (Exception)
{
MessageBox.Show("Стоимость должна быть числом");
}
}
По условиям задачи мы должны вычислить среднюю цену для выделенных элементов списка (я на вскидку не нашёл как преобразовать IList в IEnumerable, поэтому тупо перебираем список выбранных элементов, считаем сумму и, заодно, собираем список идентификаторов для последующего переопределения цены)
/*
обработчик события клика по кнопке "Изменить стоимость на..." в главном окне
*/
private void CostChangeButton_Click(object sender, RoutedEventArgs e)
{
decimal sum = 0;
List<int> idList = new List<int>();
foreach (Product item in ProductListBox.SelectedItems){
sum += item.MinCostForAgent;
idList.Add(item.Id);
}
// создаём окно, передавая ему среднюю цену
var newWindow = new EnterMinCostForAgentWindow(
sum / ProductListBox.SelectedItems.Count);
// показываем МОДАЛЬНОЕ окно
newWindow.ShowDialog();
}
Запись новой цены в БД и обновление списка.
Добавляем анализ результата модального окна
if ((bool)newWindow.ShowDialog())
{
Globals.dataProvider.setMinCostForAgent(
newWindow.Result,
idList.ToArray());
Invalidate();
}
Этот код во-первых стоит завернуть в блок try..catch, чтобы приложение не падало при ошибках и, во-вторых после сохранения суммы вывести MessageBox с сообщением, что сумма успешно изменена.
Реализация метода setMinCostForAgent:
public void setMinCostForAgent(decimal minCostForAgent, int[] ids)
{
using (MySqlConnection db = new MySqlConnection(connectionString))
{
db.Execute("UPDATE Product SET MinCostForAgent=@newCost WHERE ID in @idList",
new {
newCost = minCostForAgent,
idList = ids });
}
}
| Предыдущая лекция | Следующая лекция | |
|---|---|---|
| Пагинация, сортировка, фильтрация, поиск | Содержание | Создание, изменение продукции |