Евгений Колесников 4 meses atrás
pai
commit
443e627a03
1 arquivos alterados com 11 adições e 136 exclusões
  1. 11 136
      articles/cs_layout2.md

+ 11 - 136
articles/cs_layout2.md

@@ -14,7 +14,7 @@
 >У каждой продукции в списке отображается изображение | 0.3
 >При отсутствии изображения отображается картинка-заглушка из ресурсов | 0.3
 
-Для создания такого макета в **Авалонии** используется элемент **ListBox**
+Для создания такого макета в используется элемент **ListBox**
 
 В разметке вместо **DataGrid** вставляем **ListBox**
 
@@ -22,8 +22,7 @@
 <ListBox 
     Grid.Row="1"
     Background="White"
-    x:DataType="model:Product"
-    ItemsSource="{Binding #root.productList}">
+    ItemsSource="{Binding productList}">
     <!-- сюда потом вставить ListBox.ItemTemplate -->
 </ListBox>
 ```
@@ -65,7 +64,7 @@
 
 **В первой** колонке выводим изображение:
 
-**Авалонии** для вывода изображения нужно преобразовать имя файла в объект пиксельной графики: класс **Bitmap**. Есть два способа это сделать:
+Для вывода изображения нужно указывать URI файла. Есть два способа это сделать:
 
 * Конвертер (в принципе ничего сложного, в инете куча примеров, но я не хочу пока нагружать вас лишними сущностями)
 * Вычисляемое свойство. Этот вариант я и буду использовать. 
@@ -74,38 +73,25 @@
 <Image
     Width="64" 
     Height="64"
-    Source="{Binding ImageBitmap}" />
+    Source="{Binding ImageUri}" />
 ```
 
 
-Обратите внимание, в классе **Product** нет поля *ImageBitmap*. Для получения картинки я использую вычисляемое свойство *ImageBitmap* - в геттере проверяю есть ли такая картинка, т.к. наличие названия в базе не означает наличие файла на диске.
+Обратите внимание, в классе **Product** нет поля *ImageUri*. Для получения картинки я использую вычисляемое свойство *ImageUri* - в геттере проверяю есть ли такая картинка, т.к. наличие названия в базе не означает наличие файла на диске.
 
-Вычисляемое поле можно добавить в сгенерированный класс **Product** (файл `Models/Product.cs`), но этот файл может быть перезаписан при повторном реконструировании БД, поэтому лучше создавать свои классы в другом месте. Классы в C# могут быть описаны в нескольких файлах (главное чтобы они были в одном **namespace**), для этого используется ключевое слово **partial**:
-
-На демо экзамене есть критерии оценки за логическую и файловую структуру, поэтому куда попало классы писать не надо. Создайте каталог `Classes` и в нём класс **Product**. В созданном классе поменяйте **namespace** (напоминаю, оно должно быть таким же, как у модели) и добавьте в класс **Product** вычисляемое свойство:  
+>На демо экзамене есть критерии оценки за логическую и файловую структуру, поэтому куда попало классы писать не надо. Создайте каталог `Classes` и в нём класс **Product**. В созданном классе поменяйте **namespace** (напоминаю, оно должно быть таким же, как у модели) и добавьте в класс **Product** вычисляемое свойство:  
 
 ```cs
-namespace AvaloniaApplication1.esmirnov;
+namespace Application1.esmirnov;
 
 public partial class Product
 {
-    public Bitmap? ImageBitmap
+    public Uri ImageUri
     {
         get
         {
             var imageName = Environment.CurrentDirectory + (Image ?? "");
-            // windows лояльно относится к разным слешам в пути, 
-            // а вот linux не находит такие файлы, 
-            // поэтому меняю обратные слеши на прямые
-            imageName = imageName.Replace('\\', '/');
-
-            // если файл существует, то возвращаю его
-            // иначе картинку заглушку
-            var result = System.IO.File.Exists(imageName) ? 
-                new Bitmap(imageName) :
-                new Bitmap(Environment.CurrentDirectory+"/picture.png");
-
-            return result;
+            return System.IO.File.Exists(imageName) ? new Uri(imageName) : null;
         }
     }
 }
@@ -145,15 +131,9 @@ public string TypeAndName
 }
 ```
 
-Артикул выводится как есть
-
-**Строка материалов** (вычисляемое свойство *MaterialString*) должна формироваться динамически по таблице связей **ProductMaterial**, про неё раскажу ниже. Пока пишем заглушку:
+Артикул и строку материалов выводим как есть
 
-```cs
-public string MaterialString { get; } = "тут будет список используемых  материалов";
-```
-
-**В третьей** колонке выводим **сумму материалов**, т.е. опять динамически будем формировать по таблице связей.
+**В третьей** колонке выводим **сумму материалов**.
 
 ```xml
 <TextBlock 
@@ -161,111 +141,6 @@ public string MaterialString { get; } = "тут будет список испо
     Text="{Binding MaterialSum}"/>
 ```
 
-И пока тоже заглушка:
-
-```cs
-public string MaterialSum { get; } = "тут будет сумма используемых  материалов";
-```
-
-Если мы сейчас запустим наше приложение, то не увидим **тип материала**. Дело в том, что по-умолчанию в модель загружаются данные только текущей таблицы (**Product**), а виртуальное свойство **ProductType** остаётся не заполненным. 
-
-![](../img/rider012.png)
-
-Для того, чтобы считать связанные данные, нужно при чтении данных использовать метод **Include** (можно несколько раз для нескольких связанных таблиц):
-
->Количество включений не ограничено, но всё сразу лучше не загружать - C# достаточно "умный", чтобы вычислять нужные свойства только при отображении, поэтому *строку материалов* и *сумму* можно считать отдельно
-
-Меняем в конструкторе код получения данных:
-
-```cs
-using (var context = new esmirnovContext())
-{
-    productList = context.Products
-        .Include(product => product.ProductType)
-        .Include(product => product.ProductMaterials)
-        .ToList();
-}
-```
-
-Теперь типы выводятся нормально:
-
-![](../img/rider013.png)
-
-## Расчёт материалов
-
-Материалы (название и цену) мы можем взять из таблицы **Material**, которая связана с продуктами (**Product**) отношением *многие-ко-многим* через таблицу **ProductMaterial**. Массив этих связей мы в продукты уже включили (*product.ProductMaterials*), осталось выбрать материалы (переписываем заглушки в файле `Classes/Product.cs`): 
-
-```cs
-private string? _materialString = null;
-private double _materialSum = 0;
-
-public string MaterialString
-{
-    get
-    {
-        if (_materialString == null)
-        {
-            using (var context = new esmirnovContext())
-            {
-                _materialString = "";
-                foreach (var item in ProductMaterials)
-                {
-                    var material = context.Materials
-                        .Where(m => m.Id == item.MaterialId).First();
-
-                    _materialString += material?.Title + ", ";
-
-                    _materialSum += Convert.ToDouble(material?.Cost ?? 0) *
-                        (item.Count ?? 0);
-                }
-            }
-        }
-        return _materialString;
-    }
-}
-
-public double MaterialSum
-{
-    get {
-        return _materialSum;
-    }
-}
-```
-
-Что тут происходит?
-
-**Во-первых**, чтобы каждый раз не пересчитывать данные мы их кешируем:
-
-```cs
-private string? _materialString = null;
-private double _materialSum = 0;
-```
-
-Если материалы продукта вычисляются в первый раз (значение равно **null**), то происходит реальное чтение из базы, иначе возвращаем ранее вычисленное значение.
-
-**Во-вторых**, перебираем список материалов и формируем строку и сумму материалов
-
-```cs
-// перебираем массив материалов продукта 
-// (значения из связи ProductMaterials, 
-// полученные вместе с основным запросом к базе)
-foreach (var item in ProductMaterials)
-{
-    // ищем материал по его Id
-    var material = context.Materials
-        .Where(m => m.Id == item.MaterialId)
-        .First();
-
-    // формируем строку
-    _materialString += material?.Title + ", ";
-
-    // и цену, учитывая количество материалов
-    _materialSum += Convert.ToDouble(material?.Cost ?? 0) * (item.Count ?? 0);
-}
-```
-
-Теперь отображается всё что требуется по заданию, причём мы не написали ни одного запроса к БД, всё за нас сделал ORM фреймворк.
-
 ![](../img/rider014.png)
 
 ## Вывод данных "плиткой"