|
|
@@ -81,7 +81,7 @@
|
|
|
```
|
|
|
|
|
|
|
|
|
-Обратите внимание, в классе **Product** нет поля *ImageBitmap*. Для получения картинки я использую вычисляемое свойство *ImagePreview* - в геттере проверяю есть ли такая картинка, т.к. наличие названия в базе не означает наличие файла на диске.
|
|
|
+Обратите внимание, в классе **Product** нет поля *ImageBitmap*. Для получения картинки я использую вычисляемое свойство *ImageBitmap* - в геттере проверяю есть ли такая картинка, т.к. наличие названия в базе не означает наличие файла на диске.
|
|
|
|
|
|
Вычисляемое поле можно добавить в сгенерированный класс **Product** (файл `Models/Product.cs`), но этот файл может быть перезаписан при повторном реконструировании БД, поэтому лучше создавать свои классы в другом месте. Классы в C# могут быть описаны в нескольких файлах (главное чтобы они были в одном **namespace**), для этого используется ключевое слово **partial**:
|
|
|
|
|
|
@@ -114,24 +114,7 @@ public partial class Product
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-<!--
|
|
|
-1. Файлы подгружаемые с диска должны быть в формате **Uri**, иначе программа ищет их в ресурсах исполняемого файла
|
|
|
-1. К имени файла добавляю путь к текущему каталогу
|
|
|
-1. Если такого файла нет, то возвращаю **null**, в этом случае срабатывает параметр привязки *TargetNullValue* - отображать изображение по-умолчанию.
|
|
|
-1. Изображение по-умолчанию задается в ресурсах окна (первый элемент в теге Window)
|
|
|
-
|
|
|
- ```xml
|
|
|
- <Window.Resources>
|
|
|
- <BitmapImage
|
|
|
- x:Key='defaultImage'
|
|
|
- UriSource='./Images/picture.png' />
|
|
|
- </Window.Resources>
|
|
|
- ```
|
|
|
-
|
|
|
- тут, как раз, указывается путь к изображению в ресурсах (в моём случае в приложении создан каталог `Images` и в него ЗАГРУЖЕН файл)
|
|
|
--->
|
|
|
-
|
|
|
-**Во второй** колонке вывожу основную информацию о продукте: тип + название, аритикул и список материалов.
|
|
|
+**Во второй** колонке вывожу основную информацию о продукте: _тип_ + _название_, _аритикул_ и _список материалов_.
|
|
|
|
|
|
Так как данные выводятся в несколько строк, то заворачиваю их в **StackPanel** (тут можно использовать и **Grid**, но их и так уже много в разметке)
|
|
|
|
|
|
@@ -152,7 +135,7 @@ public partial class Product
|
|
|
</StackPanel>
|
|
|
```
|
|
|
|
|
|
-Вообще выводимый текст можно форматировать, но чтобы не запоминать лишних сущностей можно нарисовать ещё одно вычисляемое свойство *TypeAndName* (в том же классе **Product**)
|
|
|
+Вообще выводимый текст можно форматировать сразу в разметке, но чтобы не запоминать лишних сущностей можно нарисовать ещё одно вычисляемое свойство *TypeAndName* (в том же классе **Product**)
|
|
|
|
|
|
```cs
|
|
|
public string TypeAndName
|
|
|
@@ -167,7 +150,7 @@ public string TypeAndName
|
|
|
|
|
|
Артикул выводится как есть
|
|
|
|
|
|
-Строка материалов (вычисляемое свойство *MaterialString*) должна формироваться динамически по таблице связей **ProductMaterial**, про неё раскажу ниже. Пока пишем заглушку:
|
|
|
+**Строка материалов** (вычисляемое свойство *MaterialString*) должна формироваться динамически по таблице связей **ProductMaterial**, про неё раскажу ниже. Пока пишем заглушку:
|
|
|
|
|
|
```cs
|
|
|
public string MaterialString { get; } = "тут будет список используемых материалов";
|
|
|
@@ -187,13 +170,13 @@ public string MaterialString { get; } = "тут будет список испо
|
|
|
public string MaterialSum { get; } = "тут будет сумма используемых материалов";
|
|
|
```
|
|
|
|
|
|
-Если мы сейчас запустим наше приложение, то не увидим тип материала. Дело в том, что по-умолчанию в модель загружаются данные только текущей таблицы (**Product**), а виртуальное свойство **ProductType** остаётся не заполненным.
|
|
|
+Если мы сейчас запустим наше приложение, то не увидим **тип материала**. Дело в том, что по-умолчанию в модель загружаются данные только текущей таблицы (**Product**), а виртуальное свойство **ProductType** остаётся не заполненным.
|
|
|
|
|
|

|
|
|
|
|
|
Для того, чтобы считать связанные данные, нужно при чтении данных использовать метод **Include** (можно несколько раз для нескольких связанных таблиц):
|
|
|
|
|
|
->Количество включений не ограничено, но всё сразу лучше не загружать - C# достаточно "умный", чтобы вычислять нужные свойства только при отображении, поэтому строку материалов и сумму можно считать отдельно
|
|
|
+>Количество включений не ограничено, но всё сразу лучше не загружать - C# достаточно "умный", чтобы вычислять нужные свойства только при отображении, поэтому *строку материалов* и *сумму* можно считать отдельно
|
|
|
|
|
|
Меняем в конструкторе код получения данных:
|
|
|
|
|
|
@@ -211,33 +194,6 @@ using (var context = new esmirnovContext())
|
|
|
|
|
|

|
|
|
|
|
|
-<!--
|
|
|
-Видно, что размер элемента зависит от содержимого.
|
|
|
-
|
|
|
-Чтобы это исправить нужно добавить в **ListView** стиль для элемента контейнера, в котором задать горизонтальное выравнивание по ширине:
|
|
|
-
|
|
|
-```xml
|
|
|
-<ListView
|
|
|
- Grid.Row="1"
|
|
|
- Grid.Column="1"
|
|
|
- ItemsSource="{Binding ProductList}"
|
|
|
->
|
|
|
- <ListView.ItemContainerStyle>
|
|
|
- <Style
|
|
|
- TargetType="ListViewItem">
|
|
|
- <Setter
|
|
|
- Property="HorizontalContentAlignment"
|
|
|
- Value="Stretch" />
|
|
|
- </Style>
|
|
|
- </ListView.ItemContainerStyle>
|
|
|
- ...
|
|
|
-```
|
|
|
-
|
|
|
-Теперь окно должно выглядеть как положено:
|
|
|
-
|
|
|
-
|
|
|
--->
|
|
|
-
|
|
|
## Расчёт материалов
|
|
|
|
|
|
Материалы (название и цену) мы можем взять из таблицы **Material**, которая связана с продуктами (**Product**) отношением *многие-ко-многим* через таблицу **ProductMaterial**. Массив этих связей мы в продукты уже включили (*product.ProductMaterials*), осталось выбрать материалы (переписываем заглушки в файле `Classes/Product.cs`):
|
|
|
@@ -285,6 +241,7 @@ public double MaterialSum
|
|
|
|
|
|
```cs
|
|
|
private string? _materialString = null;
|
|
|
+private double _materialSum = 0;
|
|
|
```
|
|
|
|
|
|
Если материалы продукта вычисляются в первый раз (значение равно **null**), то происходит реальное чтение из базы, иначе возвращаем ранее вычисленное значение.
|
|
|
@@ -318,7 +275,7 @@ foreach (var item in ProductMaterials)
|
|
|
|
|
|
Такое задание было на одном из прошлых соревнований WorldSkills, вполне вероятно что появится и на демо-экзамене.
|
|
|
|
|
|
-Компоненты **ListBox** и **ListView** по умолчанию инкапсулируют все элементы списка в специальную панель **VirtualizingStackPanel**, которая располагает все элементы по вертикали. Но с помощью свойства **ItemsPanel** можно переопределить панель элементов внутри списка.
|
|
|
+Компоненты **ListBox** и **ListView** по умолчанию инкапсулируют все элементы списка в специальную панель **VirtualizingStackPanel**, которая располагает все элементы по вертикали. Но с помощью тега **ItemsPanel** можно переопределить тип панели элементов.
|
|
|
|
|
|
Мы будем использовать уже знакомую вам **WrapPanel**:
|
|
|
|
|
|
@@ -342,16 +299,13 @@ foreach (var item in ProductMaterials)
|
|
|
|
|
|

|
|
|
|
|
|
-## Задачи на дополнительную оценку
|
|
|
-
|
|
|
-* Конвертер для отображения картинок
|
|
|
-* Разобраться с **TargetNullValue**
|
|
|
-* MVVM
|
|
|
-
|
|
|
-<table style="width: 100%;"><tr><td style="width: 40%;">
|
|
|
+<!-- <table style="width: 100%;"><tr><td style="width: 40%;">
|
|
|
<a href="../articles/cs_mysql_connection3.md">Создание подключения к БД MySQL. Получение данных с сервера.
|
|
|
</a></td><td style="width: 20%;">
|
|
|
<a href="../readme.md">Содержание
|
|
|
</a></td><td style="width: 40%;">
|
|
|
<a href="../articles/cs_pagination2.md">Пагинация, сортировка, фильтрация, поиск
|
|
|
-</a></td><tr></table>
|
|
|
+</a></td><tr></table> -->
|
|
|
+Предыдущая лекция | | Следующая лекция
|
|
|
+:----------------:|:----------:|:----------------:
|
|
|
+[Создание подключения к БД MySQL. Получение данных с сервера.](../articles/cs_mysql_connection3.md) | [Содержание](../readme.md) | [Пагинация, сортировка, фильтрация, поиск](../articles/cs_pagination2.md)
|