MVC專案實踐,在三層架構下實現SportsStore-05,實現導航

Darren Ji發表於2014-06-27

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>

執行:

13

 

為了讓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+"}
            );


執行:
14

原始碼在這裡

 

“MVC專案實踐,在三層架構下實現SportsStore”系列包括:

MVC專案實踐,在三層架構下實現SportsStore,從類圖看三層架構

MVC專案實踐,在三層架構下實現SportsStore-01,EF Code First建模、DAL層等

MVC專案實踐,在三層架構下實現SportsStore-02,DbSession層、BLL層

MVC專案實踐,在三層架構下實現SportsStore-03,Ninject控制器工廠等

MVC專案實踐,在三層架構下實現SportsStore-04,實現分頁

MVC專案實踐,在三層架構下實現SportsStore-05,實現導航

MVC專案實踐,在三層架構下實現SportsStore-06,實現購物車

MVC專案實踐,在三層架構下實現SportsStore-07,實現訂單提交

MVC專案實踐,在三層架構下實現SportsStore-08,部署到IIS伺服器

MVC專案實踐,在三層架構下實現SportsStore-09,ASP.NET MVC呼叫ASP.NET Web API的查詢服務

MVC專案實踐,在三層架構下實現SportsStore-10,連線字串的加密和解密

MVC專案實踐,在三層架構下實現SportsStore-11,使用Knockout實現增刪改查

相關文章