Wpf корзина покупателя в приложении
Корзина должна быть реализована в виде отдельного класса Basket(к примеру), далее вам нужно создать в нем поле
public ObservableCollection Products
<
get< return products;>
set < products = value;OnPropertyChanged("Products");>
>
, в который по кнопке добавить будет реализовано добавление Product.
Когда вы нажмете кнопку КУПИТЬ, то через foreach прогоняйте по Lis в вашей корзине и добавляйте в Базу данных, прикрепляя выбранный продукт к покупателю.
добавляем к нему событие CollectionChanged, который будет срабатывать при удалении и добавлении объектов в корзину.
Далее создаем поле Summ
public float Summ
<
get< return SummBasketCalculation();>
set < summ= value;OnPropertyChanged("Summ");>
>
создаем метод, который будет считать нам стоимость корзины
public float SummBasketCalculation()
// тут пишите как у вас будет считаться сумма в корзине.
return summ;
>
Так же стоит использовать интерфейс InotifyPropertyChangen для биндинга данных в в реальном времени.
Если нужно более подробно, то пишите, буду рад ответить.
Михаил СоникУченик (148) 1 год назад
Спасибо большое вам, что все расписали, я только учусь программированию, очень интересная тема 🙂 попробую разобраться)
Смотрел гайды Дударя, с одной стороны показывает как сделать что-то, с другой не понятно зачем, допустим я не понимаю, почему нужно название для команды button klick, обычно дописывают в команду что-то типа: button_reg_klick, не знаю зачем это нужно
андрей гудин Профи (835) Михаил Соник, У события есть общее название. К примеру Click, но ты его в своей программе переопределяешь и тут ты имя сам ставишь какое захочется, главное кнопку к нужному событию привязать)))
Как реализовать кнопки регулирования кол-ва товара в корзине в DataGrid WPF

В процессе реализации отображения корзины магазина понадобился функционал регулирования количества товара в самой корзине кнопками «+» и «-«. Выглядеть это дожно как-то так (прошу прощение за качество): Как такое реализовать в DataGrid, или, возможно, есть способ получше?
Отслеживать
задан 28 ноя 2022 в 12:49
TeraBasedProgrammer TeraBasedProgrammer
1 4 4 бронзовых знака
Если вы делаете все по уму, у вас используется XAML, привязки, и все в этом духе, то такое сделать элементарно, достаточно создать еще одну колонку, в которой будет 2 кнопки, привязанные к своим командами, и привязанная циферка к свойству, все. А как у вас там на самом деле, ну я лично не знаю. Если делать прям совсем по уму, то делаем отдельный контрол, который будет содержать эти 2 кнопки и циферку, а в колонке уже используем его, где просто привязываем саму циферку.
Корзина для покупок
В этой серии руководств вы узнаете об основах создания приложения ASP.NET Web Forms с помощью ASP.NET 4.5 и Microsoft Visual Studio Express 2013 для Web. В рамках этой серии руководств доступен проект Visual Studio 2013 с исходным кодом C#.
В этом руководстве описывается бизнес-логика, необходимая для добавления корзины для покупок в пример приложения Wingtip Toys ASP.NET Web Forms. Это руководство создано на основе предыдущего руководства «Отображение элементов данных и сведений» и является частью серии учебников Wingtip Toy Store. По завершении работы с этим руководством пользователи примера приложения смогут добавлять, удалять и изменять продукты в своей корзине.
Из этого руководства вы узнаете, как выполнять такие задачи:
- Как создать корзину для веб-приложения.
- Как разрешить пользователям добавлять элементы в корзину.
- Как добавить элемент управления GridView для отображения сведений о корзине покупок.
- Как вычислить и отобразить общую сумму заказа.
- Удаление и обновление элементов в корзине.
- Как включить счетчик корзины для покупок.
Функции кода в этом руководстве:
- Entity Framework Code First
- Заметки к данным
- Строго типизированные элементы управления данными
- Привязка модели
Создание корзины
Ранее в этой серии учебников вы добавили страницы и код для просмотра данных о продуктах из базы данных. В этом руководстве вы создадите корзину для управления продуктами, которые пользователи хотят купить. Пользователи смогут просматривать и добавлять элементы в корзину, даже если они не зарегистрированы или не вошли в систему. Чтобы управлять доступом к корзине покупок, вы назначите пользователям уникальный ID идентификатор с помощью глобально уникального идентификатора (GUID), когда пользователь впервые обращается к корзине. Вы сохраните его ID с помощью состояния сеанса ASP.NET.
Состояние сеанса ASP.NET — это удобное место для хранения сведений о пользователе, срок действия которых истекает после того, как пользователь покинет сайт. Хотя неправильное использование состояния сеанса может повлиять на производительность на крупных сайтах, легкое использование состояния сеанса хорошо подходит для демонстрационных целей. В примере проекта Wingtip Toys показано, как использовать состояние сеанса без внешнего поставщика, где состояние сеанса хранится внутри процесса на веб-сервере, на котором размещен сайт. Для крупных сайтов, которые предоставляют несколько экземпляров приложения, или сайтов, на которых выполняется несколько экземпляров приложения на разных серверах, рассмотрите возможность использования службы кэша Windows Azure. Эта служба кэша предоставляет распределенную службу кэширования, которая находится за пределами веб-сайта и решает проблему использования состояния внутрипроцессного сеанса. Дополнительные сведения см. в статье Использование состояния сеанса ASP.NET с веб-сайтами Windows Azure.
Добавление CartItem в качестве класса модели
Ранее в этой серии учебников вы определили схему для категории и данных продукта, создав Category классы и Product в папке Models . Теперь добавьте новый класс, чтобы определить схему для корзины. Далее в этом руководстве вы добавите класс для обработки доступа к данным к CartItem таблице. Этот класс предоставляет бизнес-логику для добавления, удаления и обновления элементов в корзине.
- Щелкните правой кнопкой мыши папку Models и выберите Добавить ->Новый элемент.

- Откроется диалоговое окно Добавление нового элемента. Выберите Код, а затем — Класс.

- Назовите этот новый класс CartItem.cs.
- Нажмите кнопку Добавить.
Новый файл класса отображается в редакторе. - Замените код по умолчанию на приведенный ниже:
using System.ComponentModel.DataAnnotations; namespace WingtipToys.Models < public class CartItem < [Key] public string ItemId < get; set; >public string CartId < get; set; >public int Quantity < get; set; >public System.DateTime DateCreated < get; set; >public int ProductId < get; set; >public virtual Product Product < get; set; >> >
Класс CartItem содержит схему, которая определяет каждый продукт, добавляемый пользователем в корзину. Этот класс аналогичен другим классам схем, созданным ранее в этой серии учебников. По соглашению Entity Framework Code First ожидает, что первичным ключом CartItem для таблицы будет или CartItemId ID . Однако код переопределяет поведение по умолчанию с помощью атрибута заметки [Key] к данным. Атрибут Key свойства ItemId указывает, что ItemID свойство является первичным ключом.
Свойство CartId указывает ID пользователя, связанного с элементом для покупки. Вы добавите код для создания этого пользователя ID , когда пользователь обращается к корзине. Он ID также будет храниться в виде переменной сеанса ASP.NET.
Обновление контекста продукта
Помимо добавления CartItem класса необходимо обновить класс контекста базы данных, который управляет классами сущностей и предоставляет доступ к данным к базе данных. Для этого необходимо добавить в класс только что созданный CartItem класс ProductContext модели.
- В Обозреватель решений найдите и откройте файл ProductContext.cs в папке Models.
- Добавьте выделенный код в файл ProductContext.cs следующим образом:
using System.Data.Entity; namespace WingtipToys.Models < public class ProductContext : DbContext < public ProductContext() : base("WingtipToys") < >public DbSet Categories < get; set; >public DbSet Products < get; set; >public DbSet ShoppingCartItems < get; set; >> >
Как упоминалось ранее в этой серии учебников, код в файле ProductContext.cs добавляет System.Data.Entity пространство имен, чтобы у вас был доступ ко всем основным функциям Entity Framework. Эта функция включает возможность запрашивать, вставлять, обновлять и удалять данные путем работы со строго типизированными объектами. Класс ProductContext добавляет доступ к только что добавленному классу CartItem модели.
Управление бизнес-логикой корзины покупок
Затем вы создадите ShoppingCart класс в новой папке Logic . Класс ShoppingCart обрабатывает доступ к данным к CartItem таблице. Класс также будет включать бизнес-логику для добавления, удаления и обновления элементов в корзине.
Добавленная логика корзины для покупок будет содержать функции для управления следующими действиями:
- Добавление элементов в корзину
- Удаление элементов из корзины
- Получение идентификатора корзины для покупок
- Получение товаров из корзины
- Подсчитывание суммы всех элементов корзины
- Обновление данных корзины
Страница корзины (ShoppingCart.aspx) и класс корзины будут использоваться вместе для доступа к данным корзины. На странице корзины будут отображаться все элементы, добавленные пользователем в корзину. Помимо страницы корзины и класса, вы создадите страницу (AddToCart.aspx) для добавления продуктов в корзину. Вы также добавите код на страницу ProductList.aspx и страницу ProductDetails.aspx , который предоставит ссылку на страницу AddToCart.aspx , чтобы пользователь смог добавить продукты в корзину.
На следующей схеме показан базовый процесс, который происходит, когда пользователь добавляет продукт в корзину.

Когда пользователь щелкает ссылку Добавить в корзину на странице ProductList.aspx или ProductDetails.aspx , приложение перейдет на страницу AddToCart.aspx , а затем автоматически на страницу ShoppingCart.aspx . Страница AddToCart.aspx добавит продукт select в корзину, вызвав метод в классе ShoppingCart. На странице ShoppingCart.aspx будут отображаться продукты, добавленные в корзину.
Создание класса Корзина покупок
Класс ShoppingCart будет добавлен в отдельную папку в приложении, чтобы было четкое различие между моделью (папка Models), страницами (корневая папка) и логикой (папка логики).
- В Обозреватель решений щелкните правой кнопкой мыши проект WingtipToysи выберите добавить новую>папку. Назовите новую папку Logic.
- Щелкните правой кнопкой мыши папку Логика и выберите Добавить ->Новый элемент.
- Добавьте новый файл класса с именем ShoppingCartActions.cs.
- Замените код по умолчанию на приведенный ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using WingtipToys.Models; namespace WingtipToys.Logic < public class ShoppingCartActions : IDisposable < public string ShoppingCartId < get; set; >private ProductContext _db = new ProductContext(); public const string CartSessionKey = "CartId"; public void AddToCart(int id) < // Retrieve the product from the database. ShoppingCartId = GetCartId(); var cartItem = _db.ShoppingCartItems.SingleOrDefault( c =>c.CartId == ShoppingCartId && c.ProductId == id); if (cartItem == null) < // Create a new cart item if no cart item exists. cartItem = new CartItem < ItemId = Guid.NewGuid().ToString(), ProductId = id, CartId = ShoppingCartId, Product = _db.Products.SingleOrDefault( p =>p.ProductID == id), Quantity = 1, DateCreated = DateTime.Now >; _db.ShoppingCartItems.Add(cartItem); > else < // If the item does exist in the cart, // then add one to the quantity. cartItem.Quantity++; >_db.SaveChanges(); > public void Dispose() < if (_db != null) < _db.Dispose(); _db = null; >> public string GetCartId() < if (HttpContext.Current.Session[CartSessionKey] == null) < if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name)) < HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name; >else < // Generate a new random GUID using System.Guid class. Guid tempCartId = Guid.NewGuid(); HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString(); >> return HttpContext.Current.Session[CartSessionKey].ToString(); > public List GetCartItems() < ShoppingCartId = GetCartId(); return _db.ShoppingCartItems.Where( c =>c.CartId == ShoppingCartId).ToList(); > > >
Метод AddToCart позволяет включать отдельные продукты в корзину на основе продукта ID . Продукт добавляется в корзину или, если корзина уже содержит товар для этого продукта, количество увеличивается.
Метод GetCartId возвращает корзину ID для пользователя. Корзина ID используется для отслеживания элементов, которые есть у пользователя в корзине. Если у пользователя нет существующей корзины ID , для него создается новая корзина ID . Если пользователь вошел в систему как зарегистрированный пользователь, в корзине ID устанавливается его имя пользователя. Однако если пользователь не выполнил вход, корзине ID присваивается уникальное значение (GUID). Идентификатор GUID гарантирует, что для каждого пользователя создается только одна корзина на основе сеанса.
Метод GetCartItems возвращает список элементов корзины для пользователя. Далее в этом руководстве вы увидите, что привязка модели используется для отображения элементов корзины в корзине GetCartItems с помощью метода .
Создание функции добавления в корзину
Как упоминалось ранее, вы создадите страницу обработки с именем AddToCart.aspx , которая будет использоваться для добавления новых продуктов в корзину пользователя. Эта страница вызовет AddToCart метод в только что созданном ShoppingCart классе. На странице AddToCart.aspx ожидается, что ей будет передан продукт ID . Этот продукт ID будет использоваться при вызове AddToCart метода в ShoppingCart классе .
Вы будете изменять код программной части (AddToCart.aspx.cs) для этой страницы, а не пользовательский интерфейс страницы (AddToCart.aspx).
Чтобы создать функцию надстройки для корзины, выполните следующие действия.

- В Обозреватель решений щелкните правой кнопкой мыши проект WingtipToysи выберите команду Добавить ->Новый элемент.
Откроется диалоговое окно Добавление нового элемента. - Добавьте стандартную новую страницу (веб-форму) в приложение с именем AddToCart.aspx.
- В Обозреватель решений щелкните правой кнопкой мыши страницу AddToCart.aspx и выберите команду Просмотреть код. Файл кода программной части AddToCart.aspx.cs открывается в редакторе.
- Замените существующий код в коде программной части AddToCart.aspx.cs следующим кодом:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Diagnostics; using WingtipToys.Logic; namespace WingtipToys < public partial class AddToCart : System.Web.UI.Page < protected void Page_Load(object sender, EventArgs e) < string rawId = Request.QueryString["ProductID"]; int productId; if (!String.IsNullOrEmpty(rawId) && int.TryParse(rawId, out productId)) < using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) < usersShoppingCart.AddToCart(Convert.ToInt16(rawId)); >> else < Debug.Fail("ERROR : We should never get to AddToCart.aspx without a ProductId."); throw new Exception("ERROR : It is illegal to load AddToCart.aspx without setting a ProductId."); >Response.Redirect("ShoppingCart.aspx"); > > >
При загрузке страницы AddToCart.aspx продукт ID извлекается из строки запроса. Затем создается экземпляр класса shopping cart, который используется для вызова AddToCart метода, добавленного ранее в этом руководстве. Метод AddToCart , содержащийся в файле ShoppingCartActions.cs , включает логику добавления выбранного продукта в корзину или увеличения количества выбранного продукта. Если продукт не был добавлен в корзину, он добавляется в таблицу CartItem базы данных. Если продукт уже добавлен в корзину, а пользователь добавляет дополнительный элемент того же продукта, количество продуктов увеличивается в CartItem таблице. Наконец, страница перенаправляется обратно на страницу ShoppingCart.aspx , которую вы добавите на следующем шаге, где пользователь увидит обновленный список элементов в корзине.
Как упоминалось ранее, пользователь ID используется для идентификации продуктов, связанных с конкретным пользователем. Он ID добавляется в строку в CartItem таблице каждый раз, когда пользователь добавляет продукт в корзину.
Создание пользовательского интерфейса корзины
На странице ShoppingCart.aspx будут отображаться продукты, добавленные пользователем в корзину. Он также предоставляет возможность добавлять, удалять и обновлять элементы в корзине.
- В Обозреватель решений щелкните правой кнопкой мыши WingtipToys и выберите команду Добавить ->Новый элемент.
Откроется диалоговое окно Добавление нового элемента. - Добавьте новую страницу (веб-форму), включающую страницу master, выбрав Веб-форма с помощью главной страницы. Назовите новую страницу ShoppingCart.aspx.
- Выберите Site.Master, чтобы присоединить страницу master к созданной aspx-странице.
- На странице ShoppingCart.aspx замените существующую разметку следующей разметкой:
"/> ", ((Convert.ToDouble(Item.Quantity)) * Convert.ToDouble(Item.Product.UnitPrice)))%>
Страница ShoppingCart.aspx содержит элемент управления GridView с именем CartList . Этот элемент управления использует привязку модели для привязки данных корзины покупок из базы данных к элементу управления GridView . При установке ItemType свойства элемента управления GridView выражение Item привязки данных доступно в разметке элемента управления и элемент управления становится строго типизированным. Как упоминалось ранее в этой серии руководств, можно выбрать сведения об объекте Item с помощью IntelliSense. Чтобы настроить элемент управления данными для использования привязки модели для выбора данных, необходимо задать SelectMethod свойство элемента управления . В приведенной выше разметке вы задали SelectMethod для использования метода GetShoppingCartItems, который возвращает список CartItem объектов . Элемент управления данными GridView вызывает метод в соответствующее время жизненного цикла страницы и автоматически привязывает возвращаемые данные. Метод GetShoppingCartItems по-прежнему необходимо добавить.
Получение элементов корзины
Затем добавьте код в код программной части ShoppingCart.aspx.cs , чтобы получить и заполнить пользовательский интерфейс корзины.
- В Обозреватель решений щелкните правой кнопкой мыши страницу ShoppingCart.aspx и выберите пункт Просмотреть код. Файл кода программной части ShoppingCart.aspx.cs открывается в редакторе.
- Замените существующий код следующим кодом:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using WingtipToys.Models; using WingtipToys.Logic; namespace WingtipToys < public partial class ShoppingCart : System.Web.UI.Page < protected void Page_Load(object sender, EventArgs e) < >public List GetShoppingCartItems() < ShoppingCartActions actions = new ShoppingCartActions(); return actions.GetCartItems(); >> >
Как упоминалось выше, GridView элемент управления данными GetShoppingCartItems вызывает метод в соответствующее время жизненного цикла страницы и автоматически привязывает возвращаемые данные. Метод GetShoppingCartItems создает экземпляр ShoppingCartActions объекта . Затем код использует этот экземпляр для возврата элементов в корзине путем вызова GetCartItems метода .
Добавление продуктов в корзину
При отображении страницы ProductList.aspx или ProductDetails.aspx пользователь сможет добавить продукт в корзину с помощью ссылки. Щелкнув ссылку, приложение переходит на страницу обработки с именем AddToCart.aspx. Страница AddToCart.aspx вызовет AddToCart метод в ShoppingCart классе, который вы добавили ранее в этом руководстве.
Теперь вы добавите ссылку Добавить в корзину на страницы ProductList.aspx и ProductDetails.aspx . Эта ссылка будет включать продукт ID , полученный из базы данных.
- В Обозреватель решений найдите и откройте страницу с именем ProductList.aspx.
- Добавьте разметку, выделенную желтым цветом, на страницу ProductList.aspx , чтобы вся страница выглядела следующим образом:
No data was returned.
"> ">
Price: <%#:String.Format("<0:c>", Item.UnitPrice)%>
"> Add To Cart
Тестирование корзины для покупок
Запустите приложение, чтобы узнать, как вы добавляете продукты в корзину.
- Нажмите клавишу F5 для запуска приложения.
После того как проект повторно создаст базу данных, откроется браузер и отобразится страница Default.aspx . - Выберите Автомобили в меню навигации по категориям.
На странице ProductList.aspx отображаются только продукты, включенные в категорию «Автомобили».
- Щелкните ссылку Добавить в корзину рядом с первым перечисленным продуктом (автомобиль-кабриолет).
Отобразится страница ShoppingCart.aspx с выбранным выбором в корзине.
- Чтобы просмотреть дополнительные продукты, выберите Плоскости в меню навигации по категориям.
- Щелкните ссылку Добавить в корзину рядом с первым перечисленным продуктом.
Страница ShoppingCart.aspx отображается с дополнительным элементом. - Закройте браузер.
Вычисление и отображение итогового заказа
Помимо добавления продуктов в корзину, вы добавите метод в ShoppingCart класс и отобразите общую GetTotal сумму заказа на странице корзины.
- В Обозреватель решений откройте файл ShoppingCartActions.cs в папке Логика.
- Добавьте в класс следующий GetTotal метод, выделенный желтым цветом ShoppingCart , чтобы класс выглядел следующим образом:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using WingtipToys.Models; namespace WingtipToys.Logic < public class ShoppingCartActions : IDisposable < public string ShoppingCartId < get; set; >private ProductContext _db = new ProductContext(); public const string CartSessionKey = "CartId"; public void AddToCart(int id) < // Retrieve the product from the database. ShoppingCartId = GetCartId(); var cartItem = _db.ShoppingCartItems.SingleOrDefault( c =>c.CartId == ShoppingCartId && c.ProductId == id); if (cartItem == null) < // Create a new cart item if no cart item exists. cartItem = new CartItem < ItemId = Guid.NewGuid().ToString(), ProductId = id, CartId = ShoppingCartId, Product = _db.Products.SingleOrDefault( p =>p.ProductID == id), Quantity = 1, DateCreated = DateTime.Now >; _db.ShoppingCartItems.Add(cartItem); > else < // If the item does exist in the cart, // then add one to the quantity. cartItem.Quantity++; >_db.SaveChanges(); > public void Dispose() < if (_db != null) < _db.Dispose(); _db = null; >> public string GetCartId() < if (HttpContext.Current.Session[CartSessionKey] == null) < if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name)) < HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name; >else < // Generate a new random GUID using System.Guid class. Guid tempCartId = Guid.NewGuid(); HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString(); >> return HttpContext.Current.Session[CartSessionKey].ToString(); > public List GetCartItems() < ShoppingCartId = GetCartId(); return _db.ShoppingCartItems.Where( c =>c.CartId == ShoppingCartId).ToList(); > public decimal GetTotal() < ShoppingCartId = GetCartId(); // Multiply product price by quantity of that product to get // the current price for each of those products in the cart. // Sum all product price totals to get the cart total. decimal? total = decimal.Zero; total = (decimal?)(from cartItems in _db.ShoppingCartItems where cartItems.CartId == ShoppingCartId select (int?)cartItems.Quantity * cartItems.Product.UnitPrice).Sum(); return total ?? decimal.Zero; >> >
GetTotal Сначала метод получает идентификатор корзины для пользователя. Затем метод получает итог корзины, умножая цену продукта на количество для каждого продукта, указанного в корзине.
В приведенном выше коде используется тип , допускающий значение NULL. int? Типы, допускаемые значением NULL, могут представлять все значения базового типа, а также в виде значения NULL. Дополнительные сведения см. в статье Использование типов, допускающих значение NULL.
Изменение отображения корзины
Далее вы измените код для страницы ShoppingCart.aspx , чтобы вызвать GetTotal метод и отобразить этот итог на странице ShoppingCart.aspx при загрузке страницы.
- В Обозреватель решений щелкните правой кнопкой мыши страницу ShoppingCart.aspx и выберите Пункт Просмотреть код.
- В файле ShoppingCart.aspx.cs обновите Page_Load обработчик, добавив следующий код, выделенный желтым цветом:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using WingtipToys.Models; using WingtipToys.Logic; namespace WingtipToys < public partial class ShoppingCart : System.Web.UI.Page < protected void Page_Load(object sender, EventArgs e) < using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) < decimal cartTotal = 0; cartTotal = usersShoppingCart.GetTotal(); if (cartTotal >0) < // Display Total. lblTotal.Text = String.Format("", cartTotal); > else < LabelTotalText.Text = ""; lblTotal.Text = ""; ShoppingCartTitle.InnerText = "Shopping Cart is Empty"; >> > public List GetShoppingCartItems() < ShoppingCartActions actions = new ShoppingCartActions(); return actions.GetCartItems(); >> >
При загрузке страницы ShoppingCart.aspx она загружает объект корзины покупок, а затем получает итог корзины, вызывая GetTotal метод ShoppingCart класса . Если корзина пуста, отображается сообщение об этом.
Тестирование всего корзины
Запустите приложение сейчас, чтобы узнать, как можно не только добавить продукт в корзину, но и просмотреть итог корзины.
- Нажмите клавишу F5 для запуска приложения.
Откроется браузер и отобразится страница Default.aspx . - Выберите Автомобили в меню навигации по категориям.
- Щелкните ссылку Добавить в корзину рядом с первым продуктом.
Отображается страница ShoppingCart.aspx с итоговой суммой заказа.
- Добавьте в корзину другие продукты (например, плоскость).
- Отобразится страница ShoppingCart.aspx с обновленным итогом по всем добавленным продуктам.

- Остановите работающее приложение, закрыв окно браузера.
Добавление кнопок обновления и оформления заказа в корзину
Чтобы разрешить пользователям изменять корзину, добавьте кнопки Обновить и Кнопки Оформления заказа на страницу корзины. Кнопка «Извлечь» используется только в дальнейшем в этой серии руководств.
- В Обозреватель решений откройте страницу ShoppingCart.aspx в корне проекта веб-приложения.
- Чтобы добавить кнопки Обновить и Проверить на страницу ShoppingCart.aspx , добавьте разметку, выделенную желтым цветом, к существующей разметке, как показано в следующем коде:
"/> ", ((Convert.ToDouble(Item.Quantity)) * Convert.ToDouble(Item.Product.UnitPrice)))%>
Когда пользователь нажимает кнопку Обновить , UpdateBtn_Click вызывается обработчик событий. Этот обработчик событий вызовет код, который вы добавите на следующем шаге.
Затем можно обновить код, содержащийся в файле ShoppingCart.aspx.cs , чтобы циклически перебирать элементы корзины и вызывать RemoveItem методы и UpdateItem .
- В Обозреватель решений откройте файл ShoppingCart.aspx.cs в корне проекта веб-приложения.
- Добавьте следующие разделы кода, выделенные желтым цветом, в файл ShoppingCart.aspx.cs :
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using WingtipToys.Models; using WingtipToys.Logic; using System.Collections.Specialized; using System.Collections; using System.Web.ModelBinding; namespace WingtipToys < public partial class ShoppingCart : System.Web.UI.Page < protected void Page_Load(object sender, EventArgs e) < using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) < decimal cartTotal = 0; cartTotal = usersShoppingCart.GetTotal(); if (cartTotal >0) < // Display Total. lblTotal.Text = String.Format("", cartTotal); > else < LabelTotalText.Text = ""; lblTotal.Text = ""; ShoppingCartTitle.InnerText = "Shopping Cart is Empty"; UpdateBtn.Visible = false; >> > public List GetShoppingCartItems() < ShoppingCartActions actions = new ShoppingCartActions(); return actions.GetCartItems(); >public List UpdateCartItems() < using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) < String cartId = usersShoppingCart.GetCartId(); ShoppingCartActions.ShoppingCartUpdates[] cartUpdates = new ShoppingCartActions.ShoppingCartUpdates[CartList.Rows.Count]; for (int i = 0; i < CartList.Rows.Count; i++) < IOrderedDictionary rowValues = new OrderedDictionary(); rowValues = GetValues(CartList.Rows[i]); cartUpdates[i].ProductId = Convert.ToInt32(rowValues["ProductID"]); CheckBox cbRemove = new CheckBox(); cbRemove = (CheckBox)CartList.Rows[i].FindControl("Remove"); cartUpdates[i].RemoveItem = cbRemove.Checked; TextBox quantityTextBox = new TextBox(); quantityTextBox = (TextBox)CartList.Rows[i].FindControl("PurchaseQuantity"); cartUpdates[i].PurchaseQuantity = Convert.ToInt16(quantityTextBox.Text.ToString()); >usersShoppingCart.UpdateShoppingCartDatabase(cartId, cartUpdates); CartList.DataBind(); lblTotal.Text = String.Format("", usersShoppingCart.GetTotal()); return usersShoppingCart.GetCartItems(); > > public static IOrderedDictionary GetValues(GridViewRow row) < IOrderedDictionary values = new OrderedDictionary(); foreach (DataControlFieldCell cell in row.Cells) < if (cell.Visible) < // Extract values from the cell. cell.ContainingField.ExtractValuesFromCell(values, cell, row.RowState, true); >> return values; > protected void UpdateBtn_Click(object sender, EventArgs e) < UpdateCartItems(); >> >
Когда пользователь нажимает кнопку Обновить на странице ShoppingCart.aspx , вызывается метод UpdateCartItems. Метод UpdateCartItems получает обновленные значения для каждого элемента в корзине. Затем метод UpdateCartItems вызывает UpdateShoppingCartDatabase метод (добавленный и описанный на следующем шаге) для добавления или удаления элементов из корзины. После обновления базы данных с учетом обновлений корзины элемент управления GridView обновляется на странице корзины покупок путем вызова DataBind метода для GridView. Кроме того, общая сумма заказа на странице корзины обновляется с учетом обновленного списка товаров.
Обновление и удаление элементов корзины
На странице ShoppingCart.aspx можно увидеть, что добавлены элементы управления для обновления количества элемента и удаления элемента. Теперь добавьте код, который сделает эти элементы управления работой.
- В Обозреватель решений откройте файл ShoppingCartActions.cs в папке Логика.
- Добавьте следующий код, выделенный желтым цветом, в файл класса ShoppingCartActions.cs :
using System; using System.Collections.Generic; using System.Linq; using System.Web; using WingtipToys.Models; namespace WingtipToys.Logic < public class ShoppingCartActions : IDisposable < public string ShoppingCartId < get; set; >private ProductContext _db = new ProductContext(); public const string CartSessionKey = "CartId"; public void AddToCart(int id) < // Retrieve the product from the database. ShoppingCartId = GetCartId(); var cartItem = _db.ShoppingCartItems.SingleOrDefault( c =>c.CartId == ShoppingCartId && c.ProductId == id); if (cartItem == null) < // Create a new cart item if no cart item exists. cartItem = new CartItem < ItemId = Guid.NewGuid().ToString(), ProductId = id, CartId = ShoppingCartId, Product = _db.Products.SingleOrDefault( p =>p.ProductID == id), Quantity = 1, DateCreated = DateTime.Now >; _db.ShoppingCartItems.Add(cartItem); > else < // If the item does exist in the cart, // then add one to the quantity. cartItem.Quantity++; >_db.SaveChanges(); > public void Dispose() < if (_db != null) < _db.Dispose(); _db = null; >> public string GetCartId() < if (HttpContext.Current.Session[CartSessionKey] == null) < if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name)) < HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name; >else < // Generate a new random GUID using System.Guid class. Guid tempCartId = Guid.NewGuid(); HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString(); >> return HttpContext.Current.Session[CartSessionKey].ToString(); > public List GetCartItems() < ShoppingCartId = GetCartId(); return _db.ShoppingCartItems.Where( c =>c.CartId == ShoppingCartId).ToList(); > public decimal GetTotal() < ShoppingCartId = GetCartId(); // Multiply product price by quantity of that product to get // the current price for each of those products in the cart. // Sum all product price totals to get the cart total. decimal? total = decimal.Zero; total = (decimal?)(from cartItems in _db.ShoppingCartItems where cartItems.CartId == ShoppingCartId select (int?)cartItems.Quantity * cartItems.Product.UnitPrice).Sum(); return total ?? decimal.Zero; >public ShoppingCartActions GetCart(HttpContext context) < using (var cart = new ShoppingCartActions()) < cart.ShoppingCartId = cart.GetCartId(); return cart; >> public void UpdateShoppingCartDatabase(String cartId, ShoppingCartUpdates[] CartItemUpdates) < using (var db = new WingtipToys.Models.ProductContext()) < try < int CartItemCount = CartItemUpdates.Count(); ListmyCart = GetCartItems(); foreach (var cartItem in myCart) < // Iterate through all rows within shopping cart list for (int i = 0; i < CartItemCount; i++) < if (cartItem.Product.ProductID == CartItemUpdates[i].ProductId) < if (CartItemUpdates[i].PurchaseQuantity < 1 || CartItemUpdates[i].RemoveItem == true) < RemoveItem(cartId, cartItem.ProductId); >else < UpdateItem(cartId, cartItem.ProductId, CartItemUpdates[i].PurchaseQuantity); >> > > > catch (Exception exp) < throw new Exception("ERROR: Unable to Update Cart Database - " + exp.Message.ToString(), exp); >> > public void RemoveItem(string removeCartID, int removeProductID) < using (var _db = new WingtipToys.Models.ProductContext()) < try < var myItem = (from c in _db.ShoppingCartItems where c.CartId == removeCartID && c.Product.ProductID == removeProductID select c).FirstOrDefault(); if (myItem != null) < // Remove Item. _db.ShoppingCartItems.Remove(myItem); _db.SaveChanges(); >> catch (Exception exp) < throw new Exception("ERROR: Unable to Remove Cart Item - " + exp.Message.ToString(), exp); >> > public void UpdateItem(string updateCartID, int updateProductID, int quantity) < using (var _db = new WingtipToys.Models.ProductContext()) < try < var myItem = (from c in _db.ShoppingCartItems where c.CartId == updateCartID && c.Product.ProductID == updateProductID select c).FirstOrDefault(); if (myItem != null) < myItem.Quantity = quantity; _db.SaveChanges(); >> catch (Exception exp) < throw new Exception("ERROR: Unable to Update Cart Item - " + exp.Message.ToString(), exp); >> > public void EmptyCart() < ShoppingCartId = GetCartId(); var cartItems = _db.ShoppingCartItems.Where( c =>c.CartId == ShoppingCartId); foreach (var cartItem in cartItems) < _db.ShoppingCartItems.Remove(cartItem); >// Save changes. _db.SaveChanges(); > public int GetCount() < ShoppingCartId = GetCartId(); // Get the count of each item in the cart and sum them up int? count = (from cartItems in _db.ShoppingCartItems where cartItems.CartId == ShoppingCartId select (int?)cartItems.Quantity).Sum(); // Return 0 if all entries are null return count ?? 0; >public struct ShoppingCartUpdates < public int ProductId; public int PurchaseQuantity; public bool RemoveItem; >> >
Метод UpdateShoppingCartDatabase , вызываемый из UpdateCartItems метода на странице ShoppingCart.aspx.cs , содержит логику обновления или удаления элементов из корзины. Метод UpdateShoppingCartDatabase выполняет итерацию по всем строкам в списке корзины для покупок. Если товар корзины помечен для удаления или количество меньше единицы, RemoveItem вызывается метод . В противном случае элемент корзины проверяется на наличие обновлений при вызове UpdateItem метода . После удаления или обновления элемента корзины сохраняются изменения базы данных.
Структура ShoppingCartUpdates используется для хранения всех элементов корзины. Метод UpdateShoppingCartDatabase использует структуру для ShoppingCartUpdates определения необходимости обновления или удаления каких-либо элементов.
В следующем руководстве вы будете использовать метод для очистки EmptyCart корзины после покупки продуктов. Но пока вы будете использовать GetCount метод, который вы только что добавили в файл ShoppingCartActions.cs , чтобы определить, сколько элементов в корзине.
Добавление счетчика корзины покупок
Чтобы разрешить пользователю просматривать общее количество элементов в корзине, добавьте счетчик на страницу Site.Master . Этот счетчик также будет выступать в качестве ссылки на корзину.
- В Обозреватель решений откройте страницу Site.Master.
- Измените разметку, добавив в раздел навигации ссылку на счетчик корзины, как показано желтым цветом, чтобы она выглядела следующим образом:
using System; using System.Collections.Generic; using System.Security.Claims; using System.Security.Principal; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Linq; using WingtipToys.Models; using WingtipToys.Logic; namespace WingtipToys < public partial class SiteMaster : MasterPage < private const string AntiXsrfTokenKey = "__AntiXsrfToken"; private const string AntiXsrfUserNameKey = "__AntiXsrfUserName"; private string _antiXsrfTokenValue; protected void Page_Init(object sender, EventArgs e) < // The code below helps to protect against XSRF attacks var requestCookie = Request.Cookies[AntiXsrfTokenKey]; Guid requestCookieGuidValue; if (requestCookie != null && Guid.TryParse(requestCookie.Value, out requestCookieGuidValue)) < // Use the Anti-XSRF token from the cookie _antiXsrfTokenValue = requestCookie.Value; Page.ViewStateUserKey = _antiXsrfTokenValue; >else < // Generate a new Anti-XSRF token and save to the cookie _antiXsrfTokenValue = Guid.NewGuid().ToString("N"); Page.ViewStateUserKey = _antiXsrfTokenValue; var responseCookie = new HttpCookie(AntiXsrfTokenKey) < HttpOnly = true, Value = _antiXsrfTokenValue >; if (FormsAuthentication.RequireSSL && Request.IsSecureConnection) < responseCookie.Secure = true; >Response.Cookies.Set(responseCookie); > Page.PreLoad += master_Page_PreLoad; > protected void master_Page_PreLoad(object sender, EventArgs e) < if (!IsPostBack) < // Set Anti-XSRF token ViewState[AntiXsrfTokenKey] = Page.ViewStateUserKey; ViewState[AntiXsrfUserNameKey] = Context.User.Identity.Name ?? String.Empty; >else < // Validate the Anti-XSRF token if ((string)ViewState[AntiXsrfTokenKey] != _antiXsrfTokenValue || (string)ViewState[AntiXsrfUserNameKey] != (Context.User.Identity.Name ?? String.Empty)) < throw new InvalidOperationException("Validation of Anti-XSRF token failed."); >> > protected void Page_Load(object sender, EventArgs e) < >protected void Page_PreRender(object sender, EventArgs e) < using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) < string cartStr = string.Format("Cart ()", usersShoppingCart.GetCount()); cartCount.InnerText = cartStr; > > public IQueryable GetCategories() < var _db = new WingtipToys.Models.ProductContext(); IQueryablequery = _db.Categories; return query; > protected void Unnamed_LoggingOut(object sender, LoginCancelEventArgs e) < Context.GetOwinContext().Authentication.SignOut(); >> >
Перед отображением страницы в формате HTML Page_PreRender возникает событие . В обработчике Page_PreRender общее количество корзины определяется путем GetCount вызова метода . Возвращаемое значение добавляется в диапазон, cartCount включенный в разметку страницы Site.Master . Теги обеспечивают правильную отрисовку внутренних элементов. При отображении любой страницы сайта отображается итог корзины. Пользователь также может щелкнуть общую сумму корзины, чтобы отобразить корзину.
Тестирование завершенной корзины покупок
Теперь вы можете запустить приложение, чтобы узнать, как добавлять, удалять и обновлять элементы в корзине. Итоговая стоимость корзины будет отражать общую стоимость всех товаров в корзине.

- Нажмите клавишу F5 для запуска приложения.
Откроется браузер со страницей Default.aspx . - Выберите Автомобили в меню навигации по категориям.
- Щелкните ссылку Добавить в корзину рядом с первым продуктом.
Отображается страница ShoppingCart.aspx с итоговой суммой заказа. - Выберите Плоскости в меню навигации по категориям.
- Щелкните ссылку Добавить в корзину рядом с первым продуктом.
- Задайте количество первого товара в корзине равным 3 и выберите поле Удалить элемент проверка второго элемента.
- Нажмите кнопку Обновить , чтобы обновить страницу корзины и отобразить новый итог заказа.
Итоги
В этом руководстве вы создали корзину для примера приложения Wingtip Toys веб-формы. В этом руководстве вы использовали Entity Framework Code First, заметки к данным, строго типизированные элементы управления данными и привязку модели.
Корзина покупок поддерживает добавление, удаление и обновление элементов, выбранных пользователем для покупки. Помимо реализации функции корзины покупок, вы узнали, как отображать элементы корзины покупок в элементе управления GridView и вычислять общую сумму заказа.
Чтобы понять, как описанная функциональность работает в реальном бизнес-приложении, можно просмотреть пример nopCommerce — ASP.NET на основе открытый код корзине для покупок электронной коммерции. Первоначально, он был построен на веб-формы и на протяжении многих лет он переехал в MVC, а теперь в ASP.NET Core.
Корзина покупок

Наше приложение продолжает расширяться, но до тех пор, пока не реализована корзина для покупок, мы не сможем продавать товары. В этой статье мы построим корзину для покупок, как показано на рисунке ниже. Это должно выглядеть знакомым всем, кто приобретал хоть что-нибудь в электронных магазинах.

Кнопка добавления в корзину («Добавить в корзину») будет отображаться рядом с каждым товаром в каталоге. Щелчок на ней будет приводить к выводу сводки по товарам, которые уже были выбраны пользователем, включая общую стоимость. В этой точке пользователь может с помощью кнопки продолжения покупки («Продолжить покупку») вернуться в каталог товаров, а с помощью кнопки перехода к оплате («Перейти к оплате») — сформировать заказ и завершить сеанс покупки.
Определение класса модели корзины
Корзина для покупок является частью предметной области приложения, поэтому для представления корзины имеет смысл создать сущность в модели предметной области. Добавьте файл класса по имени Cart.cs в папку Entities проекта GameStore.Domain и определите классы, как показано в примере ниже:
using System.Collections.Generic; using System.Linq; namespace GameStore.Domain.Entities < public class Cart < private ListlineCollection = new List(); public void AddItem(Game game, int quantity) < CartLine line = lineCollection .Where(g =>g.Game.GameId == game.GameId) .FirstOrDefault(); if (line == null) < lineCollection.Add(new CartLine < Game = game, Quantity = quantity >); > else < line.Quantity += quantity; >> public void RemoveLine(Game game) < lineCollection.RemoveAll(l =>l.Game.GameId == game.GameId); > public decimal ComputeTotalValue() < return lineCollection.Sum(e =>e.Game.Price * e.Quantity); > public void Clear() < lineCollection.Clear(); >public IEnumerable Lines < get < return lineCollection; >> > public class CartLine < public Game Game < get; set; >public int Quantity < get; set; >> >
Класс Cart использует класс CartLine, который определен в том же самом файле и представляет товар, выбранный пользователем, а также приобретаемое его количество. Мы определили методы для добавления элемента в корзину, удаления элемента из корзины, вычисления общей стоимости элементов в корзине и очистки корзины путем удаления всех элементов. Мы также предоставили свойство, которое позволяет обратиться к содержимому корзины с использованием IEnumerable. Все это было довольно легко реализовано с помощью кода C# и небольшой доли кода LINQ.
Модульное тестирование: проверка корзины
Класс Cart относительно прост, но в нем имеется несколько важных аспектов поведения, в корректной работе которых необходимо удостовериться. Неверно функционирующая корзина нарушит работу всего приложения GameStore. Мы должны протестировать каждое средство по отдельности. Для размещения этих тестов мы создадим в проекте GameStore.UnitTests новый файл модульного тестирования по имени CartTests.cs.
Первое поведение относится к добавлению элемента в корзину. При самом первом добавлении в корзину объекта Game должен быть добавлен новый экземпляр CartLine. Ниже показан тестовый метод, включая определение класса модульного тестирования:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Linq; using System.Collections.Generic; using GameStore.Domain.Entities; namespace GameStore.UnitTests < [TestClass] public class CartTests < [TestMethod] public void Can_Add_New_Lines() < // Организация - создание нескольких тестовых игр Game game1 = new Game < GameId = 1, Name = "Игра1" >; Game game2 = new Game < GameId = 2, Name = "Игра2" >; // Организация - создание корзины Cart cart = new Cart(); // Действие cart.AddItem(game1, 1); cart.AddItem(game2, 1); List results = cart.Lines.ToList(); // Утверждение Assert.AreEqual(results.Count(), 2); Assert.AreEqual(results[0].Game, game1); Assert.AreEqual(results[1].Game, game2); > > >
Однако если пользователь уже добавил объект Game в корзину, необходимо увеличить количество в соответствующем экземпляре CartLine, а не создавать новый. Модульный тест выглядит следующим образом:
// . [TestMethod] public void Can_Add_Quantity_For_Existing_Lines() < // Организация - создание нескольких тестовых игр Game game1 = new Game < GameId = 1, Name = "Игра1" >; Game game2 = new Game < GameId = 2, Name = "Игра2" >; // Организация - создание корзины Cart cart = new Cart(); // Действие cart.AddItem(game1, 1); cart.AddItem(game2, 1); cart.AddItem(game1, 5); List results = cart.Lines.OrderBy(c => c.Game.GameId).ToList(); // Утверждение Assert.AreEqual(results.Count(), 2); Assert.AreEqual(results[0].Quantity, 6); // 6 экземпляров добавлено в корзину Assert.AreEqual(results[1].Quantity, 1); >
Мы также должны проверить, что пользователи имеют возможность менять свое решение и удалять товары из корзины. Это средство реализовано в виде метода RemoveLine(). Ниже приведен необходимый тестовый метод:
// . [TestMethod] public void Can_Remove_Line() < // Организация - создание нескольких тестовых игр Game game1 = new Game < GameId = 1, Name = "Игра1" >; Game game2 = new Game < GameId = 2, Name = "Игра2" >; Game game3 = new Game < GameId = 3, Name = "Игра3" >; // Организация - создание корзины Cart cart = new Cart(); // Организация - добавление нескольких игр в корзину cart.AddItem(game1, 1); cart.AddItem(game2, 4); cart.AddItem(game3, 2); cart.AddItem(game2, 1); // Действие cart.RemoveLine(game2); // Утверждение Assert.AreEqual(cart.Lines.Where(c => c.Game == game2).Count(), 0); Assert.AreEqual(cart.Lines.Count(), 2); >
Следующее проверяемое поведение касается возможности вычисления общей стоимости элементов в корзине. Вот как выглядит соответствующий модульный тест:
// . [TestMethod] public void Calculate_Cart_Total() < // Организация - создание нескольких тестовых игр Game game1 = new Game < GameId = 1, Name = "Игра1", Price = 100 >; Game game2 = new Game < GameId = 2, Name = "Игра2", Price = 55 >; // Организация - создание корзины Cart cart = new Cart(); // Действие cart.AddItem(game1, 1); cart.AddItem(game2, 1); cart.AddItem(game1, 5); decimal result = cart.ComputeTotalValue(); // Утверждение Assert.AreEqual(result, 655); >
Последний тест очень прост. Мы должны удостовериться, что в результате очистки корзины ее содержимое корректно удаляется. Ниже показан требуемый модульный тест:
// . [TestMethod] public void Can_Clear_Contents() < // Организация - создание нескольких тестовых игр Game game1 = new Game < GameId = 1, Name = "Игра1", Price = 100 >; Game game2 = new Game < GameId = 2, Name = "Игра2", Price = 55 >; // Организация - создание корзины Cart cart = new Cart(); // Действие cart.AddItem(game1, 1); cart.AddItem(game2, 1); cart.AddItem(game1, 5); cart.Clear(); // Утверждение Assert.AreEqual(cart.Lines.Count(), 0); >
Иногда, как в этом случае, код для тестирования функциональности типа получается намного длиннее и сложнее, чем код самого типа. Не допускайте, чтобы это приводило к отказу написания модульных тестов. Дефекты в простых классах, особенно в тех, которые играют настолько важную роль, как Cart в приложении GameStore, могут оказывать разрушительное влияние.
Создание кнопок добавления в корзину
Мы должны модифицировать частичное представление Views/Shared/GameSummary.cshtml, добавив к спискам товаров кнопки. Изменения показаны в примере ниже:
@model GameStore.Domain.Entities.Game @Model.Name @Model.Price.ToString("# руб")
@using (Html.BeginForm("AddToCart", "Cart")) < @Html.HiddenFor(x => x.GameId) @Html.Hidden("returnUrl", Request.Url.PathAndQuery) > @Model.Description
Мы добавили блок Razor, который создает небольшую HTML-форму для каждого товара в списке. Отправка этой формы приводит к вызову метода действия AddToCart() из контроллера Cart (который вскоре будет реализован).
По умолчанию вспомогательный метод BeginForm() создает форму, которая использует HTTP-метод POST. Это можно изменить, обеспечив работу формы с HTTP-методом GET, но следует соблюдать осторожность. В спецификации HTTP указано, что запросы GET не должны быть изменяющими, а добавление товара в корзину определенно считается изменением.
Использование вспомогательного метода Html.BeginForm() в списке товаров означает, что каждая кнопка «Добавить в корзину» визуализируется в собственном отдельном HTML-элементе . Это может поначалу удивить, если вам ранее приходилось разрабатывать приложения с помощью ASP.NET Web Forms. В ASP.NET Web Forms существует ограничение, допускающее определение только одной формы на странице, если требуется наличие средства состояния представления или сложных элементов управления (которые обычно полагаются на состояние представления).
Поскольку в инфраструктуре ASP.NET MVC состояние представления не используется, количество форм, которые можно создавать, ничем не ограничено. Аналогично, не существует формального требования создавать форму для каждой кнопки. Однако поскольку каждая форма будет производить обратную отправку одному и тому же методу контроллера, но с разным набором значений параметров, этот подход позволяет проще и изящнее обрабатывать щелчки на кнопках.
Реализация контроллера для корзины
Для обработки щелчков на кнопках «Добавить в корзину» понадобится создать контроллер. Создайте новый контроллер по имени CartController в проекте GameStore.WebUI и приведите его содержимое в соответствие с кодом ниже:
using System.Linq; using System.Web.Mvc; using GameStore.Domain.Entities; using GameStore.Domain.Abstract; using GameStore.WebUI.Models; namespace GameStore.WebUI.Controllers < public class CartController : Controller < private IGameRepository repository; public CartController(IGameRepository repo) < repository = repo; >public RedirectToRouteResult AddToCart(int gameId, string returnUrl) < Game game = repository.Games .FirstOrDefault(g =>g.GameId == gameId); if (game != null) < GetCart().AddItem(game, 1); >return RedirectToAction("Index", new < returnUrl >); > public RedirectToRouteResult RemoveFromCart(int gameId, string returnUrl) < Game game = repository.Games .FirstOrDefault(g =>g.GameId == gameId); if (game != null) < GetCart().RemoveLine(game); >return RedirectToAction("Index", new < returnUrl >); > public Cart GetCart() < Cart cart = (Cart)Session["Cart"]; if (cart == null) < cart = new Cart(); Session["Cart"] = cart; >return cart; > > >
Относительно этого контроллера необходимо сделать несколько замечаний. Для сохранения и извлечения объектов Cart применяется средство состояния сеанса ASP.NET. Для этого предназначен метод GetCart(). Инфраструктура ASP.NET поддерживает удобное средство сеансов, которое использует cookie-наборы или переписывание URL, чтобы ассоциировать вместе множество запросов от определенного пользователя с целью формирования отдельного сеанса просмотра. С данным средством связано состояние сеанса, позволяющее ассоциировать данные с сеансом. Это идеально подходит для класса Cart.
Нам нужно, чтобы каждый пользователь имел собственную корзину, и эта корзина сохранялась между запросами. Данные, связанные с сеансом, удаляются по истечении времени существования сеанса (что обычно происходит, когда пользователь не выдает запрос в течение заданного периода), а это значит, что управлять хранением или жизненным циклом объектов Cart не понадобится.
Чтобы добавить объект в состояние сеанса, мы устанавливаем значение для определенного ключа в объекте Session примерно так, как показано ниже:
Session["Cart"] = cart;
Для извлечения объекта мы просто читаем значение с тем же самым ключом:
Cart cart = (Cart)Session["Cart"];
По умолчанию объекты состояния сеанса хранятся в памяти сервера ASP.NET, но можно сконфигурировать и другие подходы к хранению, в том числе использование базы данных SQL. Подробнее это описано в статье по приведенной выше ссылке.
Для методов AddToCart() и RemoveFromCart() применялись имена параметров, которые соответствуют элементам в HTML-формах, созданных в представлении GameSummary.cshtml. Это позволяет MVC Framework ассоциировать входящие переменные HTTP-запроса POST формы с параметрами и означает, что ничего дополнительного по обработке формы делать не придется.
Отображение содержимого корзины
Финальное замечание о контроллере Cart касается того, что методы AddToCart() и RemoveFromCart() вызывают метод RedirectToAction(). В результате этого клиентскому браузеру отправляется инструкция перенаправления HTTP, заставляя браузер запросить новый URL. В этом случае браузер запросит URL, который вызывает метод действия Index() контроллера Cart.
Мы собираемся реализовать метод Index() и применять его для отображения содержимого Cart. Если вы еще раз взглянете на рисунок вначале статьи, то увидите, что это та часть рабочего потока, которая инициируется щелчком пользователя на кнопке добавления в корзину.
Представлению, которое будет отображать содержимое корзины, необходимо передать две порции информации: объект Cart и URL для отображения, когда пользователь щелкает на кнопке «Продолжить покупку». Для этой цели мы создадим простой класс модели представления. Создайте новый файл класса по имени CartIndexViewModel.cs в папке Models проекта GameStore.WebUI. Содержимое этого файла приведено в примере ниже:
using GameStore.Domain.Entities; namespace GameStore.WebUI.Models < public class CartIndexViewModel < public Cart Cart < get; set; >public string ReturnUrl < get; set; >> >
Имея модель представления, можно реализовать метод действия Index() в CartController, как показано в примере ниже:
using System.Linq; using System.Web.Mvc; using GameStore.Domain.Entities; using GameStore.Domain.Abstract; using GameStore.WebUI.Models; namespace GameStore.WebUI.Controllers < public class CartController : Controller < public ViewResult Index(string returnUrl) < return View(new CartIndexViewModel < Cart = GetCart(), ReturnUrl = returnUrl >); > // . > >
Последний шаг при отображении содержимого корзины предусматривает создание нового представления. Щелкните правой кнопкой мыши на методе действия Index() и выберите в контекстном меню пункт Add View (Добавить представление). Установите имя представления в Index и щелкните на кнопке ОК, чтобы создать файл представления Index.cshtml. Приведите содержимое этого файла в соответствие с кодом ниже:
@model GameStore.WebUI.Models.CartIndexViewModel @ < ViewBag.Title = "GameStore: ваша корзина"; >Ваша корзина
Кол-во Игра Цена Общая цена @foreach (var line in Model.Cart.Lines) < @line.Quantity @line.Game.Name @line.Game.Price.ToString("# руб") @((line.Quantity * line.Game.Price).ToString("# руб")) > Итого: @Model.Cart.ComputeTotalValue().ToString("# руб")
Продолжить покупки
В представлении производится проход по элементам в корзине с добавлением в HTML-таблицу строки для каждого элемента. Кроме того, включается суммарная стоимость по строке и итоговая стоимость по корзине. Классы, назначенные элементам, соответствуют стилям Bootstrap для таблиц и выравнивания текста.
Теперь доступна базовая функциональность корзины для покупок. Во-первых, товары выводятся вместе с кнопками «Добавить в корзину», как показано на рисунке ниже:

И, во-вторых, щелчок на кнопке «Добавить в корзину» приводит к добавлению соответствующего товара в корзину и отображению сводной информации по корзине. Здесь можно щелкнуть на кнопке «Продолжить покупку» и вернуться на страницу товара, с которой производился переход.