轉(zhuǎn)帖|其它|編輯:郝浩|2011-03-17 13:40:33.000|閱讀 1038 次
概述:本系列是講解如何在asp.net mvc中對(duì)數(shù)據(jù)進(jìn)行展示、排序、分頁(yè)等的系列文章。在上周的文章中,一步一步教會(huì)了大家如何使用ASP.NET MVC框架去的展示數(shù)據(jù)。在上周的文章中,我們先用Visual Studio創(chuàng)建了一個(gè)新的ASP.NET MVC應(yīng)用程序,接著連接到了Northwind數(shù)據(jù)庫(kù),并展示了如何使用微軟的LINQ-SQL的工具去訪問(wèn)數(shù)據(jù)庫(kù)中的數(shù)據(jù),接著指導(dǎo)如何去實(shí)現(xiàn)視圖層去展示產(chǎn)品信息及如何設(shè)計(jì)控制器。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
本系列是講解如何在asp.net mvc中對(duì)數(shù)據(jù)進(jìn)行展示、排序、分頁(yè)等的系列文章。在上周的文章中,一步一步教會(huì)了大家如何使用ASP.NET MVC框架去的展示數(shù)據(jù)。在上周的文章中,我們先用Visual Studio創(chuàng)建了一個(gè)新的ASP.NET MVC應(yīng)用程序,接著連接到了Northwind數(shù)據(jù)庫(kù),并展示了如何使用微軟的LINQ-SQL的工具去訪問(wèn)數(shù)據(jù)庫(kù)中的數(shù)據(jù),接著指導(dǎo)如何去實(shí)現(xiàn)視圖層去展示產(chǎn)品信息及如何設(shè)計(jì)控制器。
本文是在上一篇文章的例子基礎(chǔ)上,展示了如何去實(shí)現(xiàn)數(shù)據(jù)的雙向排序。如果你是已經(jīng)熟悉ASP.NET WebForm開(kāi)發(fā)的開(kāi)發(fā)者,你應(yīng)該知道,在GridView控件中可以很簡(jiǎn)單的通過(guò)點(diǎn)擊就能實(shí)現(xiàn)排序。但可惜的是,在ASP.NET MVC中實(shí)現(xiàn)排序的功能并不是那么簡(jiǎn)單,但工作量也沒(méi)有顯著增多。在ASP.NET MVC中,我們能更多地控制網(wǎng)格和排序的界面布局和標(biāo)記,以及通過(guò)何種機(jī)制來(lái)實(shí)現(xiàn)排序。以往使用GridView控件時(shí),排序是通過(guò)將參數(shù)以POSTBACK的形式回傳到后臺(tái),以決定用什么樣的列進(jìn)行排序以及是以升序或降序-排列,回傳的參數(shù)作為隱藏表單域提交。在本文中,我們將使用查詢字符串參數(shù)來(lái)指定排序參數(shù),這意味著排序的順序可以被搜索引擎搜索到,能通過(guò)電子郵件發(fā)送給同事,還能做很多GridView內(nèi)置排序功能不能實(shí)現(xiàn)的事情。
與上一篇文章一樣,本文提供了分步的指導(dǎo)說(shuō)明,包括一個(gè)完整的可以工作的代碼例子,在文章末尾可以下載。
步驟0:一個(gè)簡(jiǎn)要指南
本文將介紹如何實(shí)現(xiàn)雙向的排序,并假定讀者已經(jīng)閱讀掌握了上一篇文章介紹的內(nèi)容。
在上一篇文章中,我們可以通過(guò)ASP.NET MVC中的URL轉(zhuǎn)發(fā)功能,以下面的地址形式訪問(wèn)產(chǎn)品的金喜正規(guī)買球:
www.yoursite.com/Products/Index(可以簡(jiǎn)寫成www.yoursite.com/Products)。本文中,我們將用下面的URL去訪問(wèn)要排序的內(nèi)容:
www.yoursite.com/Products/Sortable?sortBy=ColumnNameascending=true|false。
具體的一些例子如下:
/Products/Sortable- 這表示按默認(rèn)順序排列產(chǎn)品。當(dāng)沒(méi)指定排序的列時(shí),默認(rèn)按產(chǎn)品名稱的字母順序(如升序)排列。換句話說(shuō),如果SortBy參數(shù)沒(méi)有提供,按產(chǎn)品名稱排序,如果不提供ascending參數(shù),按遞增順序排列。
/Products/Sortable?sortBy=UnitPrice 按單價(jià)的升序排序產(chǎn)品。
/Products/Sortable?sortBy=UnitPriceascending=false – 按UnitPrice列降序排序(即從最昂貴的到價(jià)格最便宜的)。
跟使用GridView控件一樣,在點(diǎn)擊網(wǎng)格中標(biāo)題行中的列名時(shí)可以進(jìn)行。但不同于GridView的是,我們每次點(diǎn)列的這些標(biāo)題,是以超鏈接的形式實(shí)現(xiàn)的,并且?guī)в袇?shù),比
如表格中有價(jià)格這個(gè)列,當(dāng)?shù)谝淮吸c(diǎn)擊列名時(shí),將以
www.yoursite.com/Products/Sortable?sortBy=UnitPriceascending=true的形式發(fā)送鏈接到后端,請(qǐng)注意的是,在網(wǎng)格中顯示的列名,不一定跟在URL中sortBy查詢字符串參數(shù)中傳遞的名稱是一樣的。sortBy 參數(shù)提供的是在數(shù)據(jù)庫(kù)中的列名,兩者并不要求一定相同。
步驟1:創(chuàng)建指定的視圖模型
在上一篇文章的演示中,我們使用了產(chǎn)品的集合作為其實(shí)體模型(以NorthwindDataContext去命名)。這對(duì)簡(jiǎn)單的網(wǎng)格來(lái)說(shuō)是可以的,但對(duì)于要排序的數(shù)據(jù)表格,需要知道一點(diǎn)的不僅僅是產(chǎn)品的集合,還要視圖層方面知道哪些列的數(shù)據(jù)需要進(jìn)行排序,是按升序或降序排序,如果用戶要點(diǎn)的列已經(jīng)按某一個(gè)順序已排序的話,則此時(shí)會(huì)按原來(lái)的順序排序(假設(shè)某列已經(jīng)是按升序排列,用戶點(diǎn)標(biāo)題一次,則倒過(guò)來(lái)按降序排列,再點(diǎn)一次,又按升序,如此類推)。
為此,我們添加一個(gè)新類,這些類被稱為特定視圖服務(wù)的模型,打開(kāi)上一篇文章中已經(jīng)實(shí)現(xiàn)的應(yīng)用程序,在Models文件夾下添加一個(gè)名為ProductGridModel.cs 的文件,代碼如下:
namespace Web.Models
{
public class ProductGridModel
{
// Data properties
public IEnumerable Product Products { get; set; }
// Sorting-related properties
public string SortBy { get; set; }
public bool SortAscending { get; set; }
public string SortExpression
{
get
{
return this.SortAscending ? this.SortBy + " asc" : this.SortBy + " desc";
}
}
}
}
該P(yáng)roductGridModel類定義了一個(gè)產(chǎn)品屬性,它是一個(gè)集合類的屬性,用來(lái)顯示產(chǎn)品集合,同時(shí)也有三種排序相關(guān)的屬性:
SortBy
在數(shù)據(jù)庫(kù)中用來(lái)排序的數(shù)據(jù)列名稱
SortAscending
一個(gè)布爾值,指示是否用升序排序數(shù)據(jù)
SortExpression
只讀屬性,返回一個(gè)排序字符串,其構(gòu)造為SortBy和SortAscending值的組合。
例如,如果SortBy分為UnitePrice和SortAscending是true,SortExpression的值為
UnitedPrice asc。
如果SortBy設(shè)置為Discontinued 和SortAscending是false,則SortExpression返回Discontinued desc 。
步驟2:創(chuàng)建Sortable 的Action方法
在上一篇教程中,我們創(chuàng)建了一個(gè)名為ProductsController的控制器,其中有一個(gè)叫index的action和一個(gè)輔助屬性DataContext,本文中,我們將添加一個(gè)新的action方法到控制器中,并命名為Sortable,當(dāng)有來(lái)自如www.yoursite.com/Products/Sortable的請(qǐng)求時(shí),則執(zhí)行該排序方法。
ASP.NET MVC中實(shí)現(xiàn)了自動(dòng)參數(shù)綁定,來(lái)自URL或其他的參數(shù)請(qǐng)求,將被映射到執(zhí)行的實(shí)際的action中去。例如,如果你在控制器action中定義了一個(gè)輸入?yún)?shù),名為sortBy,則MVC框架將搜索傳入的請(qǐng)求的參數(shù),看是否有任何具有相同名稱的參數(shù)(在這里,一個(gè)參數(shù)可能是一個(gè)提交表單域,一個(gè)查詢字符串參數(shù)或路由參數(shù)。)如果找到一個(gè)匹配,則自動(dòng)把參數(shù)的值得賦給action中定義的參數(shù)。
下面是其實(shí)際代碼:
public class ProductsController : Controller
{
...
// GET: /Products/Sortable?SortColumn=columnNameAscending=true|false
public ActionResult Sortable(string sortBy = "ProductName", bool ascending = true)
{
var model
= new ProductGridModel()
{
SortBy
= sortBy,
SortAscending
= ascending
};
model.Products
= this.DataContext.Products.OrderBy(model.SortExpression);
return View(model);
}
}
請(qǐng)注意,action中接受兩個(gè)輸入?yún)?shù):sortBy和ascending。任何來(lái)自URL的請(qǐng)求,只要符合這兩個(gè)參數(shù)的名稱的,其值得都會(huì)被自動(dòng)匹配傳入到該action中去, 也就是說(shuō),如果有人訪問(wèn)www.yoursite.com不指定查詢字符串參數(shù),則默認(rèn)按照產(chǎn)品的名稱進(jìn)行升序排序。
Sortable的action首先創(chuàng)建一個(gè)新的ProductGridModel實(shí)例,命名為model,并且對(duì)model的SortBy和SortAscending屬性進(jìn)行賦值,接著,Sortable action獲得了產(chǎn)品的集合(this.DataContext.Products),并調(diào)用其中的OrderBy方法進(jìn)行排序,而排序的參數(shù)表達(dá)式正好是SortExpression。最后,將model模型返回給一個(gè)強(qiáng)類型的視圖,。
如果您熟悉使用LINQ,你會(huì)覺(jué)得我在這里使用的OrderBy方法有點(diǎn)奇怪,你可能會(huì)用LINQ中的lambda表達(dá)式如下這樣寫,如:this.DataContext.Products.OrderBy(p =p.ProductName)。
OrderBy方法,我使用的是不標(biāo)準(zhǔn)的LINQ,相反是微軟的動(dòng)態(tài)LINQ庫(kù)中的方法
(//weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx),它是一個(gè)庫(kù)允許使用字符串做為查詢參數(shù)。本文附件中提供了一個(gè)名為Dynamic.cs的文件(它在HelperClasses文件夾中),其中包含了OrderBy擴(kuò)展方法簽名,大家可以去學(xué)習(xí)一下。
步驟3:創(chuàng)建視圖
鼠標(biāo)右鍵點(diǎn)控制器中的Sortable action,在彈出的菜單中選擇添加視圖選項(xiàng)。從添加視圖對(duì)話框中,選中Create a strongly-typed view 復(fù)選框,然后從View data class 下拉選擇Web.Models.ProductGridModel,點(diǎn)擊確定。這時(shí)會(huì)創(chuàng)建視圖Sortable.aspx,如下圖:
接下來(lái),修改代碼如下:
table class="grid"
tr
thProduct/th
thCategory/th
thQty/Unit/th
thPrice/th
thDiscontinued/th
/tr% foreach (var item in Model.Products) { %
tr
td class="left"%: item.ProductName %/td
td class="left"%: item.Category.CategoryName %/td
td class="left"%: item.QuantityPerUnit %/td
td class="right"%: String.Format("{0:C}", item.UnitPrice) %/td
td
% if (item.Discontinued) { %
img src="%=Url.Content("~/Content/cancel.gif") %" alt="Discontinued" title="Discontinued" /
% } %
/td
/tr
% } %/table
上面的代碼跟上一篇文章中你看到的基本沒(méi)什么區(qū)別,唯一的區(qū)別,其實(shí)是在foreach語(yǔ)句中,在上一篇文章中,是:
▲
foreach(var item in Model) { ... },而本文中,其模型變成了ProductGridModel實(shí)例,其產(chǎn)品屬性包含產(chǎn)品的集合。因此,在foreach循環(huán)遍歷Model.Products。運(yùn)行后,你會(huì)發(fā)現(xiàn)訪問(wèn)頁(yè)面時(shí)默認(rèn)的是按產(chǎn)品的升序排列的:
現(xiàn)在網(wǎng)格的列標(biāo)題是文本,等下我們會(huì)將其修改為超級(jí)鏈接,但現(xiàn)在我們也可以馬上在瀏覽器中,通過(guò)輸入的方法體驗(yàn)下了,舉例來(lái)說(shuō),如果你輸入:
www.yoursite.com/Products/Sortable?sortBy=UnitPriceascending=false- 你應(yīng)該看到按 照價(jià)格從高到低排列的產(chǎn)品。
在網(wǎng)格中添加排序鏈接
此時(shí),用戶無(wú)法直觀地去排序,除非他在瀏覽器中象上面的方法輸入查詢字符串,因此我們?cè)诿總€(gè)網(wǎng)格的標(biāo)題行中提供超鏈接指向適當(dāng)?shù)木W(wǎng)址。乍一看,這可能會(huì)像一個(gè)簡(jiǎn)單的任務(wù),比如產(chǎn)品名稱列,其url應(yīng)該是
Products/Sortable?sortBy=ProductNameascending=true,而價(jià)格列,則應(yīng)該是
Products/Sortable?sortBy=UnitPriceascending=true,如此類推,歸納一下,其URL的連接方式應(yīng)該象:
Products/Sortable?sortBy=ColumnNameascending=false,同時(shí),還應(yīng)該增加一個(gè)象圖標(biāo)這樣的指示,讓用戶可以清楚地看到當(dāng)前排序的情況。
要做到這一點(diǎn),需要?jiǎng)?chuàng)建一個(gè)局部視圖。一個(gè)局部視圖看上去跟WebForms模型中的用戶控件的概念差不多。總之,這是一可以重用的視圖。
在解決方案資源管理器中的Views/Shared目錄下,鼠標(biāo)右鍵點(diǎn)擊,在彈出的菜單中選擇添加視圖,將其命名為SmartLink,并選中下面的兩個(gè)復(fù)選框,然后選擇Web.Models.ProductGridModel作為其view data class,如下圖。
單擊確定后,Visual Studio將創(chuàng)建一個(gè)新的局部視圖(SmartLink.ascx)。其中局部視圖只包含下列標(biāo)記:
%@Control
Language="C#" Inherits="System.Web.Mvc.ViewUserControlWeb.Models.ProductGridModel" %
我們現(xiàn)在來(lái)學(xué)習(xí)如何將局部視圖添加到正常的視圖中去,這可以使用下列Html.RenderParial方法之一:
% Html.RenderPartial("partialViewName"); %
% Html.RenderPartial("partialViewName", viewData); %
% Html.RenderPartial("partialViewName", model); %
% Html.RenderPartial("partialViewName", model, viewData); %
可選的參數(shù)是一個(gè)ViewDataDictionary的ViewData對(duì)象。如果提供,可以通過(guò)
ViewData["name"].去訪問(wèn)這些值。
當(dāng)要展示局部視圖的時(shí)候,我們還需要將ProductGridModel和一些額外的信息傳進(jìn)來(lái),下面的代碼展示了對(duì)于產(chǎn)品名稱一列這個(gè)表頭,我們是如何通過(guò)局部視圖去產(chǎn)生的,注意的是,我們通過(guò)ViewDataDictionary可以設(shè)置表頭中顯示的列的名稱以及該列實(shí)際對(duì)應(yīng)的是數(shù)據(jù)庫(kù)中的列名:
% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary {
{ "ColumnName", "ProductName" }, { "DisplayName", "Product" } }); %
這里設(shè)置了列名是ProductName,而顯示在表頭中的列名是Product。同理,其他表頭列也是這樣的處理,就可以把Model傳遞到部分視圖中來(lái)了。
table class="grid"
tr
th% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary { { "ColumnName", "ProductName" }, { "DisplayName", "Product" } }); %/th
th% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary { { "ColumnName", "Category.CategoryName" }, { "DisplayName", "Category" } }); %/th
th% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary { { "ColumnName", "QuantityPerUnit" }, { "DisplayName", "Qty/Unit" } }); %/th
th% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary { { "ColumnName", "UnitPrice" }, { "DisplayName", "Price" } }); %/th
th% Html.RenderPartial("SmartLink", Model, new ViewDataDictionary { { "ColumnName", "Discontinued" }, { "DisplayName" , "Discontinued" } }); %/th
/tr
...
/table
現(xiàn)在我們可以看到,從局部視圖中可以通過(guò)Model屬性訪問(wèn)在Sortable視圖中的任何值了,訪問(wèn)的方法是通過(guò)ViewData[name]即可。還要記得,我們之所以要在這里使用局部視圖,其目的為某個(gè)特定的列生成超級(jí)鏈接。
我們接下來(lái)要判斷某個(gè)列是否要升序還是降序排列,下面的代碼創(chuàng)建了isDescending變量,這個(gè)值只有當(dāng)要排序的列(由Model.SortBy產(chǎn)生)和數(shù)據(jù)庫(kù)中的列名相同(由ViewDate[ColumnName]產(chǎn)生)時(shí),并且當(dāng)前的排序?yàn)樯?Model.SortAscending)時(shí),其值才為True。
var isDescending = string.CompareOrdinal(Model.SortBy,
ViewData["ColumnName"].ToString()) == 0 Model.SortAscending;
同時(shí),我們最好通過(guò)設(shè)置CSS樣式,告訴用戶當(dāng)前的排序方向,因此我們?cè)? CustomStyles.css的CSS類定義了兩個(gè)CSS類-sortAsc和sortDesc,增加了一個(gè)向上或向下箭頭,可以用如下代碼去判斷:
f (string.CompareOrdinal(Model.SortBy, ViewData["ColumnName"].ToString()) == 0)
{
if (Model.SortAscending)
htmlAttributes.Add("class", "sortAsc");
else
htmlAttributes.Add("class", "sortDesc");
最后,完成的局部視圖代碼如下:
%
var isDescending = string.CompareOrdinal(Model.SortBy, ViewData["ColumnName"].ToString()) == 0 Model.SortAscending;
var routeData
= new RouteValueDictionary { { "sortBy", ViewData["ColumnName"].ToString() }, { "ascending", !isDescending } };
var htmlAttributes
= new Dictionarystring, object();
if (string.CompareOrdinal(Model.SortBy, ViewData["ColumnName"].ToString()) == 0)
{
if (Model.SortAscending)
htmlAttributes.Add("class", "sortAsc");
else
htmlAttributes.Add("class", "sortDesc");
}
%%: Html.ActionLink(
ViewData["DisplayName"].ToString(), // Link Text
Html.ViewContext.RouteData.Values["action"].ToString(), // Action
Html.ViewContext.RouteData.Values["controller"].ToString(), // Controller
routeData, // Route data
htmlAttributes // HTML attributes to apply to hyperlink
)
%
Html.ActionLink方法會(huì)向?yàn)g覽器端產(chǎn)生超鏈接的HTML。它的第一個(gè)參數(shù)為要顯示的文字超鏈接的標(biāo)題,這里通過(guò)ViewData[displayname]讀取。
第二個(gè)和第三個(gè)參數(shù)指定了action和控制器去生成鏈接,我們使用Html.ViewContext.RouteData.Values[action].ToString
和Html.ViewContext.RouteData.Values[controller].ToString()來(lái)獲得當(dāng)前請(qǐng)求的action和控制器,而避免了硬編碼。
第四個(gè)輸入?yún)?shù)指定了路由的數(shù)據(jù),這是我們用RouteValueDictionary字典的形式,分別向sortBy和ascending參數(shù)傳入值。
最后的參數(shù)設(shè)定了生成鏈接的HTML的CSS樣式。
當(dāng)運(yùn)行程序后,默認(rèn)是按產(chǎn)品名稱升序排序的,如下圖。
當(dāng)點(diǎn)產(chǎn)品標(biāo)題列旁邊的小箭頭時(shí),會(huì)向控制器發(fā)出如
Products/Sortable?sortBy=ProductNameascending=False的請(qǐng)求,于是產(chǎn)品名稱按降序排序了,如下圖:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:IT168