這裡,我們需要做一些事情,這些事情意味着深度改造前台:
1:為商品增加 添加到購物車 按鈕,點選後功能實作;
2:商品排序;
3:購物車預覽,以及添加 結算 按鈕;
4:一個顯式 購物車中有*個 商品 的widget;
一:添加到購物車 按鈕
修改 Views/Parts/Product.cshtml:
@{ var price = (decimal)Model.Price; var sku = (string)Model.Sku; } <article> Price: @price<br /> Sku: @sku <footer> <button>Add to shoppingcart</button> </footer> </article>
現在,商品清單上已經有了這個按鈕:
包括商品詳細頁面,也有這個按鈕。
1.1 問題
問題來了,我們發現,該按鈕在商品介紹上面,如果我們想放到下面,該怎麼做呢?
1.2 修改 Display 方法
protected override DriverResult Display(ProductPart part, string displayType, dynamic shapeHelper) { //return ContentShape("Parts_Product", () => shapeHelper.Parts_Product( // Price: part.UnitPrice, // Sku: part.Sku // )); return Combined( // Shape 1: Parts_Product ContentShape("Parts_Product", () => shapeHelper.Parts_Product( Price: part.UnitPrice, Sku: part.Sku )), // Shape 2: Parts_Product_AddButton ContentShape("Parts_Product_AddButton", () => shapeHelper.Parts_Product_AddButton()) );
在修改後的方法内,我們創造了一個新的 Shape,叫做 Parts_Product_AddButton,同時,我們使用 Combined 方法,它傳回的是依舊是 DriverResult,隻不過,它組合了兩個形狀。
這個時候,我們知道,需要建立一個 Views/Parts/Product.Addbutton.cshtml 檔案:
<button>@T("Add to shoppingcart")</button>
當然,我們得把原先的 Product.cshtml 中的代碼給恢複過來。
然後,修改 placement.info,為:
<Placement> <Place Parts_Product_Edit="Content:1" /> <Place Parts_Product="Content:0" /> <Place Parts_Product_AddButton="Content:after" /> </Placement>
然後,看到不一樣了:
二:實作 添加到購物車 功能
2.1 前台準備
首先,我們建立檔案夾 Controllers,然後控制器:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; namespace TMinji.Shop.Controllers public class ShoppingCartController : Controller { [HttpPost] public ActionResult Add(int id) { return RedirectToAction("Index"); } }
然後,修改 Views/Parts/Product.AddButton.cshtml:,
@using (Html.BeginForm("Add", "ShoppingCart", new { id = -1 })) <button type="submit">@T("Add to shoppingcart")</button>
讓它變成一個表單,并且指向到 Add 方法。
注意到,我們這裡傳遞的 id = -1,是以,我們還需要做一件事情,那就是把真是的商品 id 傳遞過來,才能添加商品。
于是乎,我們首先應該把 id 傳遞到 shape 中,修改,我們的 Display 方法,如下:
ContentShape("Parts_Product_AddButton", () => shapeHelper.Parts_Product_AddButton( ProductId: part.Id))
然後,前台 Views/Parts/Product.AddButton.cshtml 如下:
var productId = (int)Model.ProductId; @using (Html.BeginForm("Add", "ShoppingCart", new { id = productId }))
現在,就可以把值傳遞到控制器了,現在,我們需要實作業務邏輯部分。
2.2 業務邏輯之 Orchard Service
在 Models 目錄下,增加 ShoppingCartItem 實體類:
[Serializable] public sealed class ShoppingCartItem public int ProductId { get; private set; } private int _quantity; public int Quantity get { return _quantity; } set if (value < 0) throw new IndexOutOfRangeException(); _quantity = value; public ShoppingCartItem() public ShoppingCartItem(int productId, int quantity = 1) ProductId = productId; Quantity = quantity;
建立 Services 檔案夾,然後建立 IShoppingCart 接口,
public interface IShoppingCart : IDependency IEnumerable<ShoppingCartItem> Items { get; } void Add(int productId, int quantity = 1); void Remove(int productId); ProductPart GetProduct(int productId); decimal Subtotal(); decimal Vat(); decimal Total(); int ItemCount(); void UpdateItems();
然後,其實作類:
using Orchard; using Orchard.ContentManagement; using System.Web; using TMinji.Shop.Models; namespace TMinji.Shop.Services public class ShoppingCart : IShoppingCart private readonly IWorkContextAccessor _workContextAccessor; private readonly IContentManager _contentManager; public IEnumerable<ShoppingCartItem> Items { get { return ItemsInternal.AsReadOnly(); } } private HttpContextBase HttpContext get { return _workContextAccessor.GetContext().HttpContext; } private List<ShoppingCartItem> ItemsInternal get { var items = (List<ShoppingCartItem>)HttpContext.Session["ShoppingCart"]; if (items == null) { items = new List<ShoppingCartItem>(); HttpContext.Session["ShoppingCart"] = items; } return items; } public ShoppingCart(IWorkContextAccessor workContextAccessor, IContentManager contentManager) _workContextAccessor = workContextAccessor; _contentManager = contentManager; public void Add(int productId, int quantity = 1) var item = Items.SingleOrDefault(x => x.ProductId == productId); if (item == null) item = new ShoppingCartItem(productId, quantity); ItemsInternal.Add(item); else item.Quantity += quantity; public void Remove(int productId) return; ItemsInternal.Remove(item); public ProductPart GetProduct(int productId) return _contentManager.Get<ProductPart>(productId); public void UpdateItems() ItemsInternal.RemoveAll(x => x.Quantity == 0); public decimal Subtotal() return Items.Select(x => GetProduct(x.ProductId).UnitPrice * x.Quantity).Sum(); public decimal Vat() return Subtotal() * .19m; public decimal Total() return Subtotal() + Vat(); public int ItemCount() return Items.Sum(x => x.Quantity); private void Clear() ItemsInternal.Clear(); UpdateItems();
以上代碼不再一一解釋,相信大家能看明白,然後,相應的,修改控制器吧:
using Orchard.Mvc; using TMinji.Shop.Services; private readonly IShoppingCart _shoppingCart; private readonly IOrchardServices _services; public ShoppingCartController(IShoppingCart shoppingCart, IOrchardServices services) _shoppingCart = shoppingCart; _services = services; // Add the specified content id to the shopping cart with a quantity of 1. _shoppingCart.Add(id, 1); // Redirect the user to the Index action (yet to be created) public ActionResult Index() // Create a new shape using the "New" property of IOrchardServices. var shape = _services.New.ShoppingCart(); // Return a ShapeResult return new ShapeResult(this, shape);
在控制器中,我們看到了三點變化:
1:構造器接受了兩個對象,它們是被注入的,這會由 Orchard 完成;
2:Add 方法可以添加商品到購物車了;
3:增加了一個 Index 方法。可以看到在這個方法中,我們又建立了一個 Shape,而這個 Shape 的名字叫做 ShoppingCart。注意哦,它和背景建立 Shape 不一樣(記得嗎,在 Display 方法 中),這個 shape 對于那個的 cshtml 檔案為Views/ShoppingCart.cshtml:
TODO: display our shopping cart contents!
如果我們這個時候運作代碼,會發現點選 添加到購物車 後,變成 404 。這是因為,我們沒有為路由加上 area,它是什麼,是子產品名,Orchard 會根據這個 area,路由到對于的子產品中的 controller。故,我們應該修改Views/Parts/Product.AddButton.cshtml:
@using (Html.BeginForm("Add", "ShoppingCart", new { id = productId, area = "TMinji.Shop" }))
現在,繼續運作代碼,現在,我們得到錯誤:
The required anti-forgery form field "__RequestVerificationToken" is not present.
當然,這個錯誤,熟悉 MVC 的我們,已經知道怎麼修改了,修改之:
@using (Html.BeginFormAntiForgeryPost(Url.Action("Add", "ShoppingCart", new { id = productId, area = "TMinji.Shop" })))
再次運作:
我們看到,這個頁面沒有包含目前的 Theme 的母版頁,回到控制器,加一個 ThemedAttribute(當然,我們得 using Orchard.Themes;),如下:
[Themed] public ActionResult Index() // Create a new shape using the "New" property of IOrchardServices. var shape = _services.New.ShoppingCart(); // Return a ShapeResult return new ShapeResult(this, shape);
這個時候,再次運作,得到了如下的理想效果:
總結
1:前台的展現,主要通過 MVC 的控制器來實作的,而背景則繞開了控制器;
2:業務邏輯,使用 Service 機制,而不是我們自己瞎寫的類和邏輯(當然,也可以),但 Service 機制看上去更 Orchard;
3:前背景建立 Shape 的方式是不一樣的。
本文轉自最課程陸敏技部落格園部落格,原文連結:http://www.cnblogs.com/luminji/p/3860188.html,如需轉載請自行聯系原作者