SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC專案,在該專案中涵蓋了MVC的眾多方面,包括:使用DI容器、URL優化、導航、分頁、購物車、訂單、產品管理、影象上傳......是不錯的MVC實踐專案,但該專案不是放在多層框架下開發的,離真實專案還有一段距離。本系列將嘗試在多層框架下實現SportsStore專案,並用自己的方式實現一些功能。
本篇為系列第五篇,包括:
■ 8、導航
8、導航
建立NavController,派生於BaseController:
using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MySportsStore.IBLL; using Ninject; namespace MySportsStore.WebUI.Controllers { public class NavController : BaseController { [Inject] public IProductService ProductService { get; set; } public NavController() { this.AddDisposableObject(ProductService); } public PartialViewResult Menu(string category = null) { ViewBag.SelectedCategory = category; IEnumerable<string> categories = ProductService.LoadEntities(p => true).Select(p => p.Category).Distinct().OrderBy(p => p); return PartialView(categories); } } }
為什麼有category引數?
為了讓當前點選、選中的分類高亮顯示。這裡的category軌跡是:
→前端檢視點選分類名稱,並把分類名稱賦值給路由變數category
→Nav控制器的Menu()方法接收到category,把其放到ViewBag中,再次傳回前端檢視
→前端檢視在遍歷所有分類名稱的時候,如果當下分類名稱與ViewBag中的相同,就為當下分類新增一個CSS,即高亮顯示
需要為category賦上一個預設值,因為在點選分類名稱之前,category為null。
在Nav/Menu.cshtml部分檢視中,需要把category和page傳遞到Product控制器中的Nav()方法中:
@model IEnumerable<string> @Html.ActionLink("Home","List","Product") @foreach (var link in Model) { @Html.RouteLink(link, new {controller = "Product", action = "List", category = link, page = 1}, new {@class = link == ViewBag.SelectedCategory? "selected" : null}) }
在Views/Shared下的_Layout.cstml中顯示載入分類部分檢視:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> </head> <body> <div id="header"> <div class="title">體育用品商店</div> </div> <div id="categories"> @{Html.RenderAction("Menu","Nav");} </div> <div id="content"> @RenderBody() </div> @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body> </html>
根據點選分類傳遞的路由引數,在Product控制器的Nav方法中,還需要考慮到category,再對集合進行篩選。並且,還要考慮當沒有點選導航分類名稱的時候,category為null:
using System.Web.Mvc; using MySportsStore.IBLL; using MySportsStore.WebUI.Models; using Ninject; namespace MySportsStore.WebUI.Controllers { public class ProductController : BaseController { [Inject] public IProductService ProductService { get; set; } public ProductController() { this.AddDisposableObject(ProductService); } public int PageSize = 4; public ViewResult List(string category, int page = 1) { int totalCount = 0; ProductsListViewModel viewModel = new ProductsListViewModel() { Products = ProductService.LoadPageEntities(p => category == null ? true : p.Category == category, p => p.Id, PageSize, page, out totalCount, true), PagingInfo = new PagingInfo(){CurrentPage = page, ItemsPerPage = PageSize, TotalItems = category == null ? ProductService.Count(p => true) : ProductService.Count(p => p.Category == category)}, CurrentCategory = category }; return View(viewModel); } } }
以上,在檢視模型ProductsListViewModel中新增了CurrentCategory屬性,這個屬性值是要交給分頁的:
using System.Collections.Generic; using MySportsStore.Model; namespace MySportsStore.WebUI.Models { public class ProductsListViewModel { public IEnumerable<Product> Products { get; set; } public PagingInfo PagingInfo { get; set; } public string CurrentCategory { get; set; } } }
在Product/List.cshtml檢視的分頁部分,需要把CurrentCategory值賦值給路由變數category:
@model MySportsStore.WebUI.Models.ProductsListViewModel @{ ViewBag.Title = "List"; Layout = "~/Views/Shared/_Layout.cshtml"; } @foreach (var item in Model.Products) { Html.RenderPartial("PrductSummary", item); } <div class="pager"> @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x, category = Model.CurrentCategory})) </div>
執行:
為了讓URL更好看,需要考慮如下情境下的URL:
● 執行預設頁的時候
● 點選分頁的時候
● 點選導航分類的時候
● 點選導航分類後,再點選分頁的時候
調整URL為:
routes.MapRoute( null, "", //匹配空的URL,如"/" new{controller = "Product", action = "List", category = (string)null, page = 1} ); routes.MapRoute( null, "Page{page}", //匹配"/Page1",當點選分頁的時候 new {controller = "Product", action = "List", category = (string)null}, new {page = @"\d+"} //約束page為數字 ); routes.MapRoute( null, "{category}", //匹配 "/Soccer",當點選導航分類的時候 new {controller = "Product", action = "List", page = 1} ); routes.MapRoute( null, "{category}/Page{page}", //匹配"/Soccer/Page1",當點選導航分類,在點選分頁的時候 new {controller = "Product", action = "List"}, new {page = @"\d+"} );
原始碼在這裡。
“MVC專案實踐,在三層架構下實現SportsStore”系列包括: