Browse Source

расписал разметку окна продукции

Evgeny Kolesnikov 4 năm trước cách đây
mục cha
commit
268c3d1781
7 tập tin đã thay đổi với 192 bổ sung15 xóa
  1. 158 0
      articles/cs_layout.md
  2. 33 15
      articles/cs_mysql_connection2.md
  3. BIN
      data/variant1.zip
  4. BIN
      data/variant2.zip
  5. BIN
      img/01066.png
  6. BIN
      img/01067.png
  7. 1 0
      readme.md

+ 158 - 0
articles/cs_layout.md

@@ -0,0 +1,158 @@
+<table style="width: 100%;"><tr><td style="width: 40%;">
+<a href="../articles/cs_mysql_connection2.md">Создание подключения к БД MySQL. Получение данных с сервера.
+</a></td><td style="width: 20%;">
+<a href="../readme.md">Содержание
+</a></td><td style="width: 40%;">
+<a href="../articles/cs_layout.md">Вывод данных согласно макету (ListView, Image).
+</a></td><tr></table>
+
+# Вывод данных согласно макету (ListView, Image).
+
+>Напоминаю как выглядит макет списка продукции
+>![](../img/product_list_layout.jpg)
+
+Для создания такого макета используется элемент **ListView**
+
+В разметке вместо **GridView** вставляем **ListView**
+
+```xml
+<ListView
+    Grid.Row="1"
+    Grid.Column="1"
+    ItemsSource="{Binding ProductList}"
+>
+
+</ListView>
+```
+
+Внутри него вставляем макет для элемента списка: пока у нас только прямоугольная рамка со скругленными углами (в этом макете вроде скрулять не надо, возможно осталось от другого шаблона)
+
+```xml
+<ListView.ItemTemplate>
+    <DataTemplate>
+        <Border 
+            BorderThickness="1" 
+            BorderBrush="Black" 
+            CornerRadius="5">
+
+            <!-- сюда потом вставить содержимое -->
+
+        </Border>
+    </DataTemplate>
+</ListView.ItemTemplate>                
+```
+
+Внутри макета вставляем **Grid** из трёх колонок: для картинки, основного содержимого и стоимости.
+
+```xml
+<Grid 
+    Margin="10" 
+    HorizontalAlignment="Stretch">
+
+    <Grid.ColumnDefinitions>
+        <ColumnDefinition Width="64"/>
+        <ColumnDefinition Width="*"/>
+        <ColumnDefinition Width="auto"/>
+    </Grid.ColumnDefinitions>
+
+    <!-- сюда потом вставить содержимое -->
+
+</Grid>
+```
+
+В первой колонке выводим изображение:
+
+```xml
+<Image
+    Width="64" 
+    Height="64"
+    Source="{Binding ImagePreview,TargetNullValue={StaticResource defaultImage}}" />
+```
+
+Обратите внимание, вместо поля *Image* я вывожу вычисляемое поле *ImagePreview* - в геттере проверяю есть ли такая картинка, т.к. наличие данных в базе не означает наличие файла на диске
+
+```cs
+public Uri ImagePreview {
+    get {
+        var imageName = Environment.CurrentDirectory + (Image ?? "");
+        return System.IO.File.Exists(imageName) ? new Uri(imageName) : null;
+    }
+}
+```
+
+1. Файлы подгружаемые с диска должны быть в формате **Uri**, иначе программа ищет их в ресурсах исполняемого файла
+2. К имени файла добавляю путь к текущему каталогу 
+3. Если такого файла нет, то возвращаю **null**, в этом случае срабатывает параметр привязки *TargetNullValue* - отображать изображение по-умолчанию.
+4. Изображение по-умолчанию задается в ресурсах окна (первый элемент окна)
+
+    ```xml
+    <Window.Resources>
+        <BitmapImage 
+            x:Key='defaultImage' 
+            UriSource='./Images/picture.png' />
+    </Window.Resources>
+    ```
+
+    тут, как раз, указывается путь к изображению в ресурсах (в моём случае в приложении сознад каталог `Image` и в него ЗАГРУЖЕН файл)
+
+Во второй колонке вывожу основную информацию о продукте: тип + название, ариткул и список материалов.
+
+Так как данные выводятся в несколько строк, то заворачиваю их в **StackPanel** (тут можно использовать и **Grid**, но их и так уже много в разметке)
+
+```xml
+<StackPanel
+    Grid.Column="1"
+    Margin="5"
+    Orientation="Vertical">
+
+    <TextBlock 
+        Text="{Binding TypeAndName}"/>
+
+    <TextBlock 
+        Text="{Binding ArticleNumber}"/>
+
+    <TextBlock 
+        Text="{Binding MaterialString}"/>
+</StackPanel>
+```
+
+Вообще выводимый текст можно форматировать, но чтобы не запоминать лишних сущностей можно нарисовать ещё один геттер *TypeAndName*
+
+```cs
+public string TypeAndName {
+    get {
+        return ProductTypeTitle+" | "+Title;
+    }
+}
+```
+
+Артикул и список материалов выводятся как есть
+
+На данный момент приложение выглядит примерно так
+
+![](../img/01066.png)
+
+Видно, что размер элемента зависит от содержимого.
+
+Чтобы это исправить нужно добавить в **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>
+    ...
+```
+
+Теперь окно должно выглядеть как положено:
+
+![](../img/01067.png)

+ 33 - 15
articles/cs_mysql_connection2.md

@@ -3,11 +3,9 @@
 </a></td><td style="width: 20%;">
 <a href="../readme.md">Содержание
 </a></td><td style="width: 40%;">
-<a href="../articles/cs_mysql_connection2.md">---
+<a href="../articles/cs_layout.md">Вывод данных согласно макету (ListView, Image).
 </a></td><tr></table>
 
-# Создание подключения к БД MySQL. Получение данных с сервера.
-
 Дальше мы продолжим разбор задания прошлогоднего демо-экзамена. 
 
 Базу мы развернули и данные в неё импортировали, теперь начнём разбор второй сессии: создание desktop-приложения.
@@ -24,7 +22,9 @@
 >
 >Стоимость продукта должна быть рассчитана исходя из используемых материалов.
 
-По макету видно, что на первом экране уже нужны почти все данные, которые мы импортировали ранее: список продуктов (Product), список материалов (Material) продукта (через таблицу ProductMaterial).
+# Создание подключения к БД MySQL. Получение данных с сервера.
+
+По макету видно, что на первом экране уже нужны почти все данные, которые мы импортировали ранее: наименование продукта и артикул (таблица **Product**), тип продукта (**ProductType**), список материалов и стоимость материалов (**Material** через **ProductMaterial**).
 
 Есть несколько вариантов работы с данными:
 
@@ -34,8 +34,6 @@
 
 * **WPF** "заточена" на работу с объектами. И так как от **Entity** мы отказались, то будем вручную создавать модели и грузить в них данные с помощью **DataReader**-a
 
->В рамках демо-экзамена требуется работать с моделями ("Основные сущности представлены отдельными классами", но стоит это всего 0,2 балла).
-
 ## Создание моделей
 
 Шаблон приложения [берём](https://github.com/kolei/OAP/blob/master/articles/wpf_template.md) из лекций прошлого года.
@@ -73,6 +71,8 @@ LEFT JOIN
     ) pp ON pp.ProductID = p.ID
 ```
 
+Приведенный запрос выбирает все продукты, добавляет поле *тип продукта* из словаря и поля *список материалов* и *стоимость материалов* из подзапроса, который использует таблицу связей и таблицу материалов
+
 >Про **LEFT JOIN** я раньше не рассказывал, в принципе это аналог добавления второй таблицы в секцию **FROM**, только условие добавления описывается не в секции **WHERE** а в параметре **ON**
 
 ### Модель "Продукт" (с данными о материалах)
@@ -99,11 +99,11 @@ public class Product
 }
 ```
 
-Если вы не уверены, что сможете написать сводный SQL-запрос, то описывайте остальные модели. Мы потом разберем, как извлечь сводные данные с помощью LINQ-запросов. Но на демо-экзамене можете сразу остальные модели не делать, а только если останется время, т.к. основная работа будет над таблицей **Product**
+>Если вы не уверены, что сможете написать сводный SQL-запрос, то описывайте остальные модели. Мы потом разберем, как извлечь сводные данные с помощью LINQ-запросов. Но на демо-экзамене можете сразу остальные модели не делать, а только если останется время, т.к. основная работа будет над таблицей **Product**
 
 ## Получение данных из базы
 
-1. Создаем интерфейс поставщика данных
+1. Создаем интерфейс поставщика данных (он в шаблоне приложения уже есть)
 
     ```cs
     interface IDataProvider
@@ -130,7 +130,8 @@ public class Product
         {
             try
             {
-                Connection = new MySqlConnection("Server=kolei.ru;Database=ТУТ ВАША БАЗА;port=3306;UserId=ТУТ ВАШ ЛОГИН;password=ТУТ ПАРОЛЬ;");
+                Connection = new MySqlConnection(
+                    "Server=kolei.ru;Database=ТУТ ВАША БАЗА;port=3306;UserId=ТУТ ВАШ ЛОГИН;password=ТУТ ПАРОЛЬ;");
             }
             catch (Exception)
             {
@@ -163,15 +164,21 @@ public class Product
 
             try
             {
+                // открываем соединение с сервером
                 Connection.Open();
                 try
                 {
+                    // создаем команду
                     MySqlCommand Command = new MySqlCommand(Query, Connection);
+                    // получаем результат команды (массив строк)
                     MySqlDataReader Reader = Command.ExecuteReader();
 
+                    // перебираем стоки
                     while (Reader.Read())
                     {
+                        // создаем экземпляр класса 
                         Product NewProduct = new Product();
+                        // и заполняем его поля
                         NewProduct.ID = Reader.GetInt32("ID");
                         NewProduct.Title = Reader.GetString("Title");
                         NewProduct.ProductTypeID = Reader.GetInt32("ProductTypeID");
@@ -190,11 +197,14 @@ public class Product
                         NewProduct.MaterialString = Reader["MaterialList"].ToString();
                         NewProduct.Total = Reader["Total"].ToString();
 
+                        // добавляем экземпляр класса в список продуктов
                         ProductList.Add(NewProduct);
                     }
                 }
                 finally
                 {
+                    // обязательно закрываем соединение
+                    // ресурсы сервера конечны
                     Connection.Close();
                 }
             }
@@ -263,15 +273,15 @@ public class Product
 
 ## Получение связанных данных (словари и связи многие-ко-многим)
 
->Для тех, кто не осилит сводный SQL-запрос
+>Это нужно только если вы не осилите сводный SQL-запрос. Если и с LINQ-запросами проблемы, то лучше сосредоточтесь на создании диаграммы прецедентов и спецификации к ней, а в программе выведите только список продукции без всяких связей.
 
 Нам нужно:
 
-* вывести тип продукта
+* [вывести тип продукта](#получение-типа-продукта)
+* [вывести список материалов](#получение-списка-материалов)
 * подсчитать сумму материалов
-* вывести список материалов
 
-### Получение типа продукта (словарь)
+### Получение типа продукта
 
 1. Рисуем модель **ProductType**
 
@@ -344,7 +354,7 @@ public class Product
     }
     ```
 
-3. В класс **Product** добавляем геттер, для вычисления типа продукции
+3. В класс **Product** добавляем геттер, для получения названия типа продукции
 
     ```cs
     public string LinqTitle {
@@ -359,7 +369,7 @@ public class Product
 
 4. В разметке теперь можем использовать поле *LinqTitle* для отображения типа продукции.
 
-### Получение списка материалов (многие-ко-многим)
+### Получение списка материалов
 
 >Тут подробно расписывать не буду, всё как в предыдущей части, просто покажу результирующий геттер
 
@@ -386,3 +396,11 @@ public string LinqMaterials {
     }
 }
 ```
+
+<table style="width: 100%;"><tr><td style="width: 40%;">
+<a href="../articles/sql_import.md">Создание базы данных. Импорт данных.
+</a></td><td style="width: 20%;">
+<a href="../readme.md">Содержание
+</a></td><td style="width: 40%;">
+<a href="../articles/cs_layout.md">Вывод данных согласно макету (ListView, Image).
+</a></td><tr></table>

BIN
data/variant1.zip


BIN
data/variant2.zip


BIN
img/01066.png


BIN
img/01067.png


+ 1 - 0
readme.md

@@ -120,6 +120,7 @@ http://sergeyteplyakov.blogspot.com/2014/01/microsoft-fakes-state-verification.h
 
 1. [Создание подключения к БД MySQL. Получение данных с сервера.](./articles/cs_mysql_connection2.md)
 
+2. [Вывод данных согласно макету (ListView, Image).](./articles/cs_layout.md)
 
 <!--