# Вывод списка материалов продукта. CRUD материалов продукта
>**CRUD** - аббревиатура от слов **C**reate, **R**ead, **U**pdate, **D**elete - основные операции, которые вы должны уметь реализовывать с любым набором данных.
>**Задание:**
>Необходимо реализовать вывод списка материалов, используемых при производстве продукции, с указанием количества. В список можно добавлять новые позиции и удалять существующие. При добавлении материалы должны выбираться из выпадающего списка с возможностью поиска по наименованию.
Сначала хотел, чтобы этот материал вы сделали самостоятельно, но при реализации возникло несколько новых моментов, поэтому распишу в этой лекции
* [Read](#read-вывод-списка)
* [Delete](#delete-удаление-материала-продукта)
В итоге должно получиться что-то подобное (список материалов продукта под картинкой):

## Read (вывод списка)
Получаем из базы список материалов *редактируемого продукта* и выводим этот список используя **ListView**
1. Получение списка материалов редактируемого продукта.
Список формируем в конструкторе окна **EditProductWindow**.
Материалы продукта (в принципе это очевидно по названию) хранятся в таблице **ProductMaterial**. Это, так называемая, **таблица связей** - реализация отношения *многие (продукты) - ко - многим (материалам)*. При чтении надо учитывать, что нам нужны материалы только редактируемого продукта, т.е. указать фильтр по редактируемому продукту при выборке:
```cs
public IEnumerable 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
```
Рассмотрим подробнее реализацию кнопки "Удалить":
- вместо элемента **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();
}
}
```
Составной первичный ключ в таблице **ProductMaterial**
