Преглед на файлове

список материалов продукта, удаление элемента списка

Евгений Колесников преди 3 години
родител
ревизия
55d962fc0f
променени са 3 файла, в които са добавени 153 реда и са изтрити 0 реда
  1. 151 0
      articles/cs_product_material.md
  2. BIN
      img/cs008.png
  3. 2 0
      readme.md

+ 151 - 0
articles/cs_product_material.md

@@ -0,0 +1,151 @@
+<table style="width: 100%;"><tr><td style="width: 40%;">
+<a href="../articles/cs_edit_product2">Добавление/редактирование продукции
+</a></td><td style="width: 20%;">
+<a href="../readme.md">Содержание
+</a></td><td style="width: 40%;">
+<!-- <a href="../articles/cs_layout2.md">Вывод данных согласно макету (ListView, Image).</a> -->
+</td><tr></table>
+
+# Вывод списка материалов продукта. CRUD материалов продукта
+
+>**CRUD** - аббревиатура от слов **C**reate, **R**ead, **U**pdate, **D**elete - основные операции, которые вы должны уметь реализовывать с любым набором данных.
+
+>**Задание:**
+>Необходимо реализовать вывод списка материалов, используемых при производстве продукции, с указанием количества. В список можно добавлять новые позиции и удалять существующие. При добавлении материалы должны выбираться из выпадающего списка с возможностью поиска по наименованию.
+
+Сначала хотел, чтобы этот материал вы сделали самостоятельно, но при реализации возникло несколько новых моментов, поэтому распишу в этой лекции
+
+* [Read](#read-вывод-списка)
+* [Delete](#delete-удаление-материала-продукта)
+
+## Read (вывод списка)
+
+Получаем из базы список материалов *редактируемого продукта* и выводим этот список используя **ListView**
+
+1. Получение списка материалов редактируемого продукта. 
+
+    Список формируем в конструкторе окна **EditProductWindow**. 
+    
+    Материалы продукта (в принципе это очевидно по названию) хранятся в таблице **ProductMaterial**. Это, так называемая, **таблица связей**  - реализация отношения *многие (продукты) - ко - многим (материалам)*. При чтении надо учитывать, что нам нужны материалы только редактируемого продукта, т.е. указать фильтр по редактируемому продукту при выборке: 
+
+    ```cs
+    public IEnumerable<ProductMaterial> ProductMaterialList { get; set; }
+
+    public EditProductWindow(Product EditProduct)
+    {
+        InitializeComponent();
+        DataContext = this;
+        CurrentProduct = EditProduct;
+        using (var context = new dbContext())
+        {
+            ProductTypeList = context.ProductTypes.ToList();
+        }
+
+        // то что выше у вас уже было
+
+        // чтение списка материалов завернём в отдельный метод,
+        // т.к. его придётся перечитывать при удалении, редактировании и добавлении   
+        LoadProductMaterials();
+    }
+
+    private LoadProductMaterials()
+    {
+        using (var context = new dbContext())
+        {
+            ProductMaterialList = context.ProductMaterials
+                // фильтр по продукту
+                .Where(pm => pm.ProductId == CurrentProduct.Id)
+                // включая информацию о материалах (нам нужно название)
+                .Include(pm => pm.Material)
+                .ToList();
+        }
+        Invalidate("ProductMaterialList");
+    }
+    ```
+
+2. Вывод списка материалов продукта
+
+    Тут обычный **ListView**, но в качестве одного из элементов мы нарисуем кнопку "Удалить", чтобы удалять элемент списка можно было не заходя в окно редактирования
+
+    ```xml
+    <ListView
+        ItemsSource="{Binding ProductMaterialList}"
+        x:Name="ProductMaterialtListView" 
+        MouseDoubleClick="ProductMaterialtListView_MouseDoubleClick"
+    >
+        <ListView.ItemContainerStyle>
+            <Style 
+                TargetType="ListViewItem"
+            >
+                <Setter 
+                    Property="HorizontalContentAlignment"
+                    Value="Stretch" />
+            </Style>
+        </ListView.ItemContainerStyle>
+        <ListView.ItemTemplate>
+            <DataTemplate>
+                <Grid >
+                    <!-- в списке 3 колонки: название материала, количество и кнопка удаления -->
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition/>
+                        <ColumnDefinition Width="auto"/>
+                        <ColumnDefinition Width="auto"/>
+                    </Grid.ColumnDefinitions>
+                    <!-- тут вы уже должны сами сообразить как получить название материала -->
+                    <TextBlock 
+                        Text="{Binding Material}"/>
+                    <!-- этой колонке добавим границы слева и справа -->
+                    <TextBlock     
+                        Grid.Column="1" 
+                        Margin="10,0"
+                        Text="{Binding Count}"/>
+                    <!-- кнопка "удалить" -->
+                    <TextBlock
+                        x:Name="DeleteMaterialTextBlock" 
+                        Grid.Column="2"
+                        Tag="{Binding Path=.}"
+                        Text="🗑" 
+                        MouseDown="DeleteMaterialTextBlock_MouseDown"/>
+                </Grid>
+            </DataTemplate>
+        </ListView.ItemTemplate>
+    </ListView>
+    ```
+
+    Рассмотрим подробнее реализацию кнопки "Удалить":
+
+    - вместо элемента **Button** используем элемент **TextBlock** (стандартная кнопка выглядит слишком тяжеловесно в списке)
+    - в качестве текста используем UTF символ корзины 
+    - для того чтобы знать на каком элементе списка мы кликнули, сохраняем в атрубуте **Tag** ссылку на текущий элемент списка (**Path=.**). Атрибут **Tag** есть у всех визуальных элементов и в нём может храниться любой объект. 
+
+## Delete (удаление материала продукта)
+
+Реализуем обработчик клика по кнопке удаления:
+
+```cs
+private void DeleteMaterialTextBlock_MouseDown(object sender, MouseButtonEventArgs e)
+{
+    // sender (в параметрах метода) содержит указатель на визуальный элемент, по которому мы кликнули
+    // (sender as TextBlock) приводит объект к типу TextBlock
+    // (sender as TextBlock).Tag as ProductMaterial - атрибут Tag мы приводим к классу ProductMaterial
+    var productMaterial = (sender as TextBlock).Tag as ProductMaterial;
+
+    using (var context = new dbContext())
+    {
+        // при поиске удаляемого материала нужно учитывать, 
+        // что у него составной первичный ключ и указывать поля ключа 
+        // в том же порядке, в котором они перечислены в первичном ключе
+        var deletedProductMaterial = context.ProductMaterials
+            .Find(productMaterial.ProductId, productMaterial.MaterialId);
+
+        context.ProductMaterials.Remove(deletedProductMaterial);
+        
+        if (context.SaveChanges() > 0)
+            LoadProductMaterials();
+    }
+}
+```
+
+На этот момент должно получиться что-то подобное (кнопка "Добавить" ещё не реализована):
+
+![](../img/cs008.png)

BIN
img/cs008.png


+ 2 - 0
readme.md

@@ -240,6 +240,8 @@ https://office-menu.ru/uroki-sql Уроки SQL
 
 1. [Создание, изменение продукции](./articles/cs_edit_product2.md)
 
+1. [Вывод списка материалов продукта. CRUD материалов продукта](./articles/cs_product_material.md)
+
 ## Тема 5.1.5. Разработка своего API.
 
 1. [API. PHP-сервер. GET-запрос.](./articles/api_php.md)