(四) View/Model 全解(mvc)
轉(zhuǎn)自:http://www.cnblogs.com/zhangziqiu/archive/2009/03/18/Aspnet-MVC-4.html
?
一.摘要
本文講解在Action中向View傳遞Model的幾種方式.以及View獲取Model以后如何編寫(xiě)顯示邏輯.還詳細(xì)的介紹了ASP.NET MVC框架提供的Html Helper類的使用及如何為Html Helper類添加自定義擴(kuò)展方法.
二.承上啟下
上一篇文章中我們學(xué)習(xí)了Controller處理一次請(qǐng)求的全過(guò)程.在Controller的Action中, 會(huì)傳遞數(shù)據(jù)給View,還會(huì)通知View對(duì)象開(kāi)始顯示.所以Model是在Action中獲取的, 并由Action傳遞給View. View對(duì)象接到Action通知后會(huì)使用自己的顯示邏輯展示頁(yè)面.
下面首先讓我們學(xué)習(xí)如何將Model傳遞給View對(duì)象.
三.傳遞數(shù)據(jù)給View
在MVC中,Model對(duì)象是指包含了數(shù)據(jù)的模型. Controller將Model傳遞給View以后, View對(duì)象中不應(yīng)該做任何的業(yè)務(wù)邏輯處理, 僅僅根據(jù)Model對(duì)象做一些顯示邏輯的處理.
傳遞Model對(duì)象時(shí), 我們有兩種選擇:
1.傳遞一個(gè)弱類型的集合, 即成員為object類型的集合,? 在View中需要將每個(gè)成員轉(zhuǎn)換成我們需要的類型,比如int, string,自定義類型等.
2.傳遞強(qiáng)類型對(duì)象, 這些類型是我們自定義的. 在View中直接使用我們傳遞的強(qiáng)類型對(duì)象, 不需要再轉(zhuǎn)換類型.
如果讓我們自己設(shè)計(jì)一個(gè)MVC框架, 我們也會(huì)想到上面兩種實(shí)現(xiàn)方式,接下來(lái)看看在ASP.NET MVC中的實(shí)現(xiàn).
1.傳遞弱類型的集合
(1) 如何傳遞
ASP.NET MVC框架定義了ViewContext類, 直譯后是"View上下文", 其中保存和View有關(guān)的所有數(shù)據(jù), 其中Model對(duì)象也封裝在了此類型中.
ViewContext對(duì)象包含三個(gè)屬性:
- IView View
- ViewDataDictionary ViewData
- TempDataDictionary TempData
其中ViewData集合和TempData集合都是用來(lái)保存Model對(duì)象的.在一個(gè)Controller的Action中, 我們可以用如下方式為這兩個(gè)集合賦值:
/// <summary> /// 傳遞弱類型Model的Action示例 /// </summary> /// <returns>ViewResult</returns> public ActionResult WeakTypedDemo() { ViewData["model"] = "Weak Type Data in ViewData"; TempData["model"] = "Weak Type Data in TempData"; return View("WeakTypedDemo"); }?
在頁(yè)面中, 是用如下方式使用這兩個(gè)集合:
<div> <% = ViewData["model"] %><br /> <% = TempData["model"] %><br /> </div>
?
(2) 傳遞過(guò)程
請(qǐng)注意Action中的賦值語(yǔ)句實(shí)際上操作的是Controller類的ViewData和TempData屬性, 此時(shí)并沒(méi)有任何的數(shù)據(jù)傳遞.上一篇文章中我們已經(jīng)學(xué)到, return View語(yǔ)句會(huì)返回一個(gè)ViewResult對(duì)象, 并且接下來(lái)要執(zhí)行ViewResult的Executeresult方法. Controller的View方法會(huì)將Controller類的ViewData和TempData屬性值傳遞給ViewResult,代碼如下:
protected internal virtual ViewResult View(IView view, object model) { if (model != null) { ViewData.Model = model; } return new ViewResult { View = view, ViewData = ViewData, TempData = TempData }; }然后在ViewResult中根據(jù)ViewData和TempData構(gòu)建ViewContext對(duì)象:
public override void ExecuteResult(ControllerContext context) { //... ViewContext viewContext = new ViewContext(context, View, ViewData, TempData); View.Render(viewContext, context.HttpContext.Response.Output); //... }
?
ViewContext對(duì)象最終會(huì)傳遞給ViewPage, 也就是說(shuō)ViewData和TempData集合傳遞到了ViewPage. 我這里簡(jiǎn)化了最后的傳遞流程, 實(shí)際上ViewData對(duì)象并不是通過(guò)ViewContext傳遞到ViewPage中的, ViewPage上的ViewData是一個(gè)單獨(dú)的屬性, 并沒(méi)有像TempData一樣其實(shí)訪問(wèn)的是ViewContext.TempData. 這么做容易產(chǎn)生奇異, 本類ViewContext是一個(gè)很好理解職責(zé)十分清晰的類. 作為使用者的我們暫時(shí)可以忽略這點(diǎn)不足, 因?yàn)槿绱藢?shí)現(xiàn)ViewData完全是為了下面使用強(qiáng)類型對(duì)象.
(3)ViewData和TempData的區(qū)別
雖然ViewData和TempData都可以傳遞弱類型數(shù)據(jù),但是兩者的使用是有區(qū)別的:
- ViewData的生命周期和View相同, 只對(duì)當(dāng)前View有效.
- TempData保存在Session中, Controller每次執(zhí)行請(qǐng)求的時(shí)候會(huì)從Session中獲取TempData并刪除Session, 獲取完TempData數(shù)據(jù)后雖然保存在內(nèi)部的字典對(duì)象中,但是TempData集合的每個(gè)條目訪問(wèn)一次后就從字典表中刪除. 也就是說(shuō)TempData的數(shù)據(jù)至多只能經(jīng)過(guò)一次Controller傳遞.
(4) TempData的實(shí)現(xiàn)
TempData的類型是TempDataDictionary, 和一般的字典表沒(méi)有明顯的不同, TempData的生命周期是由Controll決定的.
在所有Controll的基類ControllerBase中, 創(chuàng)建了類型為TempDataDictionary的TempData屬性.
在ControllerBase的派生類Controller中, 重寫(xiě)了ExecuteCore()方法:
protected override void ExecuteCore() { TempData.Load(ControllerContext, TempDataProvider); try { string actionName = RouteData.GetRequiredString("action"); if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { TempData.Save(ControllerContext, TempDataProvider); } }注意其中的TempData.Load和TempData.Save語(yǔ)句.
TempDataDictionary.Load用來(lái)從ControllerContext總讀取TempData的數(shù)據(jù).
TempDataDictionary.Save方法將發(fā)生了變化的TempData數(shù)據(jù)保存到ControllerContext中.
這兩個(gè)方法都需要傳遞ITempDataProvider實(shí)例負(fù)責(zé)具體的讀取和保存操作. 在Controll中默認(rèn)的TempDataProvider是SessionStateTempDataProvider, 也就是說(shuō)讀取和保存都使用Session. 我們也可以擴(kuò)展自己的TempDataProvider, 可以將臨時(shí)數(shù)據(jù)保存在任何地方.比如制作AspNetCacheTempDataProvider使用機(jī)器本地緩存來(lái)保存TempData.
為何TempData只能夠在Controll中傳遞一次? 因?yàn)镾essionStateTempDataProvider.LoadTempData方法(在TempDataDictionary.Load中調(diào)用)在從ControllerContext的Session中讀取了TempData數(shù)據(jù)后, 會(huì)清空Session:
public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext) { HttpContextBase httpContext = controllerContext.HttpContext; if (httpContext.Session == null) { throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled); } Dictionary<string, object> tempDataDictionary = httpContext.Session[TempDataSessionStateKey] as Dictionary<string, object>; if (tempDataDictionary != null) { // If we got it from Session, remove it so that no other request gets it httpContext.Session.Remove(TempDataSessionStateKey); return tempDataDictionary; } else { return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); } }
注意上面加粗的部分. 一旦讀取成功, 就會(huì)刪除TempData的Session.
再回憶一下Controll的ExecuteCore方法,? 是在Controll的Execute方法中調(diào)用的, 是每一次Controll一定會(huì)執(zhí)行的方法, 所以我們得出了"只能在Controll之間傳遞一次"的結(jié)論.
?
?
2.傳遞強(qiáng)類型對(duì)象
我在系統(tǒng)中建立了一個(gè)模型類:StrongTypedDemoDTO
從名字可以看出, 這個(gè)模型類是數(shù)據(jù)傳輸時(shí)使用的(Data Transfer Object).而且是我為一個(gè)View單獨(dú)創(chuàng)建的.
添加一個(gè)傳遞強(qiáng)類型Model的Action,使用如下代碼:
public ActionResult StrongTypedDemo() { StrongTypedDemoDTO model = new StrongTypedDemoDTO() { UserName="ziqiu.zhang", UserPassword="123456" }; return View(model); }使用了Controller.View()方法的一個(gè)重載, 將model對(duì)象傳遞給View對(duì)象.下面省略此對(duì)象的傳輸過(guò)程, 先讓我們來(lái)看看如何在View中使用此對(duì)象.
在創(chuàng)建一個(gè)View時(shí), 會(huì)彈出下面的彈出框:
勾選"Create a strongly-typed view"即表示要?jiǎng)?chuàng)建一個(gè)強(qiáng)類型的View, 在"View data class"中選擇我們的數(shù)據(jù)模型類.
在"view content"中如下選項(xiàng):
這里是選擇我們的View的"模板", 不同的模板會(huì)生成不同的View頁(yè)面代碼. 雖然這些代碼不一定滿足我們需要, 但是有時(shí)候的確能節(jié)省一些時(shí)間,尤其是在寫(xiě)文章做Demo的時(shí)候. 比如我們的View是添加數(shù)據(jù)使用的,那就選擇"Create".如果是顯示一條數(shù)據(jù)用的, 就選擇"Detail".
以選擇Detail為例, 自動(dòng)生成了下列代碼:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<DemoRC.Models.DTO.TransferModelController.StrongTypedDemoDTO>" %> ... <body> <fieldset> <legend>Fields</legend> <p> UserName: <%= Html.Encode(Model.UserName) %> </p> <p> UserPassword: <%= Html.Encode(Model.UserPassword) %> </p> </fieldset> <p> <%=Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) %> | <%=Html.ActionLink("Back to List", "Index") %> </p> </body> ...
頁(yè)面的Model屬性就是一個(gè)強(qiáng)類型對(duì)象, 在這里就是StrongTypedDemoDTO類實(shí)例.page頁(yè)面指令可以看出, 這里的頁(yè)面繼承自ViewPage<T>類, 而不是ViewPage, 用T已經(jīng)確定為StrongTypedDemoDTO類型, 所以Model的類型就是StrongTypedDemoDTO.
3.傳遞數(shù)據(jù)的思考
使用強(qiáng)類型數(shù)據(jù)要優(yōu)于弱類型數(shù)據(jù), 老趙也曾提出過(guò). 強(qiáng)類型有太多的好處, 智能提示, 語(yǔ)意明確, 提高性能,編譯時(shí)發(fā)現(xiàn)錯(cuò)誤等等.
所以在實(shí)際應(yīng)用中, 我們應(yīng)該傳遞強(qiáng)類型的數(shù)據(jù).
目前ASP.NET MVC還存在一些不足. 將頁(yè)面類型化,? 導(dǎo)致了只能傳遞一種數(shù)據(jù)類型實(shí)例到頁(yè)面上. 而且內(nèi)部代碼的實(shí)現(xiàn)上并不十分完美.尤其是雖然我們已經(jīng)知道傳遞的是StrongTypedDemoDTO類型, 頁(yè)面的Model屬性也是StrongTypedDemoDTO類型, 但是仍然需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換, 原因是Controller的View(object model)方法重載接收的是一個(gè)object類型.
還有, 為每個(gè)View建立一個(gè)模型類, 也是一件繁瑣的工作. 也許我們的業(yè)務(wù)模型中的兩個(gè)類組合在一起就是View頁(yè)面需要的數(shù)據(jù), 但是卻不得不建立一個(gè)類將其封裝起來(lái).模型類的膨脹也是需要控制一個(gè)事情. 尤其是對(duì)于互諒網(wǎng)應(yīng)用而非企業(yè)內(nèi)部的系統(tǒng), 頁(yè)面往往會(huì)有成百上千個(gè).而且復(fù)用較少.
當(dāng)然目前來(lái)說(shuō)既然要使用強(qiáng)類型的Model, 我提出一些組織Model類型的實(shí)踐方法.下面是我項(xiàng)目中的Model類型組織結(jié)構(gòu):
這里Model是一個(gè)文件夾, 稍大一些的系統(tǒng)可以建立一個(gè)Model項(xiàng)目. 另外我們需要建立一個(gè)DTO文件夾, 用來(lái)區(qū)分Model的類型. MVC中的Model應(yīng)該對(duì)應(yīng)DTO文件夾中的類.在DTO中按照Controller再建立文件夾, 因?yàn)锳ction和View大部分都是按照Controller組織的, 所以Model也應(yīng)該按照Controller組織.
在Controller文件夾里放置具體的Model類. 其實(shí)兩個(gè)Controller文件夾中可以同相同的類名稱, 我們通過(guò)命名空間區(qū)分同名的Model類:
namespace DemoRC.Models.DTO.TransferModelController { /// <summary> /// Action為StrongTypedDemo的數(shù)據(jù)傳輸模型 /// </summary> public class StrongTypedDemoDTO { /// <summary> /// 用戶名 /// </summary> public string UserName { get; set; } /// <summary> /// 用戶密碼 /// </summary> public string UserPassword { get; set; } } }使用時(shí)也要通過(guò)帶有Controller的命名空間使用比如DTO.TransferModelController.StrongTypedDemoDTO, 或者建立一些自己的約定.
四.使用Model輸出頁(yè)面
View對(duì)象獲取了Model以后, 我們可以通過(guò)兩種方式使用數(shù)據(jù):
1.使用內(nèi)嵌代碼
熟悉ASP,PHP等頁(yè)面語(yǔ)言的人都會(huì)很熟悉這種直接在頁(yè)面上書(shū)寫(xiě)代碼的方式.但是在View中應(yīng)該只書(shū)寫(xiě)和顯示邏輯有關(guān)的代碼,而不要增加任何的業(yè)務(wù)邏輯代碼.
假設(shè)我們創(chuàng)建了下面這個(gè)Action,為ViewData添加了三條記錄:
/// <summary> /// Action示例:使用內(nèi)嵌代碼輸出ViewData /// </summary> /// <returns></returns> public ActionResult ShowModelWithInsideCodeDemo() { ViewData["k1"] = @"<script type=""text/javascript"">"; ViewData["k2"] = @"alert(""Hello ASP.NET MVC !"");"; ViewData["k3"] = @"</script>"; return View("ShowModelWithInsideCode"); }
?
?
在ShowModelWithInsideCode中, 我們可以通過(guò)內(nèi)嵌代碼的方式, 遍歷ViewData集合:
<html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>使用內(nèi)嵌代碼輸出ViewData</title> <% foreach(KeyValuePair<string, object> item in ViewData ) {%> <% = item.Value %> <% } %> </head> <body> <div> <div>此頁(yè)面運(yùn)行的腳本代碼為:</div> <fieldset> <% foreach(KeyValuePair<string, object> item in ViewData ) {%> <% = Html.Encode(item.Value) %> <br /> <% } %> </fieldset> </div> </body> </html>頁(yè)面上遍歷了兩遍ViewData,第一次是作為腳本輸出的, 第二次由于進(jìn)行了HTML編碼,所以將作為文字顯示在頁(yè)面上.
使用這種方式, 我們可以美工做好的HTML頁(yè)面的動(dòng)態(tài)部分, 使用<% %>的形式轉(zhuǎn)化為編碼區(qū)域, 通過(guò)程序控制輸出.由于只剩下顯示邏輯要處理,所以這種開(kāi)發(fā)方式往往要比CodeBehind的編碼方式更有效率, 維護(hù)起來(lái)一目了然.
最讓我高興是使用這種方式后,我們終于可以只使用HTML控件了.雖然ASP.NET WebFrom編程模型中自帶了很多服務(wù)器控件, 功能很好很強(qiáng)大, 但是那終究是別人開(kāi)發(fā)的控件, 這些控件是可以隨意變化的, 而且實(shí)現(xiàn)原理也對(duì)使用者封閉. 使用原始的頁(yè)面模型和HTML控件將使我們真正的做程序的主人.而且不會(huì)因?yàn)槊魈旆?wù)器控件換了個(gè)用法就要更新知識(shí), 要知道幾乎所有的HTML控件幾乎是被所有瀏覽器支持且不會(huì)輕易改變的.
2.使用服務(wù)器控件
注意雖然我們同樣可以在ASP.NET MVC中使用服務(wù)器端控件, 但是在MVC中這并不是一個(gè)好的使用方式.建議不要使用.
要使用服務(wù)器端控件, 我們就需要在后臺(tái)代碼中為控件綁定數(shù)據(jù). ASP.NET MVC框架提供的添加一個(gè)View對(duì)象的方法已經(jīng)不能創(chuàng)建后臺(tái)代碼, 也就是說(shuō)已經(jīng)摒棄了這種方式.但是我們?nèi)匀豢梢宰约禾砑?
首先創(chuàng)建一個(gè)帶有后臺(tái)代碼的(.cs文件),一般的Web Form頁(yè)面(aspx頁(yè)面),然后修改頁(yè)面的繼承關(guān)系, 改為繼承自ViewPage:
public partial class ShowModelWithControl : System.Web.Mvc.ViewPage?
在頁(yè)面上放置一個(gè)Repeater控件用來(lái)顯示數(shù)據(jù):
<body> <form id="form1" runat="server"> <div> <asp:Repeater ID="rptView" runat="server"> <ItemTemplate> <%# ((KeyValuePair<string, object>)Container.DataItem).Value %><br /> </ItemTemplate> </asp:Repeater> </div> </form> </body>在Page_Load方法中, 為Repeater綁定數(shù)據(jù):
public partial class ShowModelWithControl : System.Web.Mvc.ViewPage { protected void Page_Load(object sender, EventArgs e) { rptView.DataSource = ViewData; rptView.DataBind(); } }在Controller中創(chuàng)建Action, 為ViewData賦值:
/// <summary> /// Action示例:使用服務(wù)器控件輸出ViewData /// </summary> /// <returns></returns> public ActionResult ShowModelWithControlDemo() { ViewData["k1"] = @"This"; ViewData["k2"] = @"is"; ViewData["k3"] = @"a"; ViewData["k4"] = @"page"; return View("ShowModelWithControl"); }運(yùn)行結(jié)果:
再次強(qiáng)調(diào),? 在ASP.NET MVC中我們應(yīng)該盡量避免使用這種方式.
3.使用 HTML Helper 類生成HTML控件
HTML Helper類是ASP.NET MVC框架中提供的生成HTML控件代碼的類. 本質(zhì)上與第一種方式一樣, 只是我們可以不必手工書(shū)寫(xiě)HTML代碼,而是借助HTML Helper類中的方法幫助我們生成HTML控件代碼.
同時(shí),我們也可以使用擴(kuò)展方法為HTML Helper類添加自定義的生成控件的方法.
HTML Helper類的大部分方法都是返回一個(gè)HTML控件的完整字符串, 所以可以直接在需要調(diào)用的地方使用<% =Html.ActionLink() %>的形式輸出字符串.
(1)ASP.NET MVC中的HtmlHelper類
在ViewPage中提供了Html屬性, 這就是一個(gè)HtmlHelper類的實(shí)例. ASP.NET MVC框架自帶了下面這些方法:
- Html.ActionLink()
- Html.BeginForm()
- Html.CheckBox()
- Html.DropDownList()
- Html.EndForm()
- Html.Hidden()
- Html.ListBox()
- Html.Password()
- Html.RadioButton()
- Html.TextArea()
- Html.TextBox()
上面列舉的常用的HtmlHelper類的方法,并不是完整列表.
下面的例子演示如何使用HtmlHelper類:
<div> <% using (Html.BeginForm()) { %> <label style="width:60px;display:inline-block;">用戶名:</label> <% =Html.TextBox("UserName", "ziqiu.zhang", new { style="width:200px;" })%> <br /><br /> <label style="width:60px;display:inline-block;">密碼:</label> <% =Html.Password("Psssword", "123456", new { style = "width:200px;" })%> <% }%> </div>上面的代碼使用Html.BeginForm輸出一個(gè)表單對(duì)象, 并在表單對(duì)象中添加了兩個(gè)Input, 一個(gè)使用Html.TextBox輸出, 另一個(gè)使用Html.Password輸出,區(qū)別是Html.Password輸出的input控件的type類型為password.效果如圖:
(2)擴(kuò)展Html Helper類
我們可以自己擴(kuò)展HtmlHelper類, 為HtmlHelper類添加新的擴(kuò)展方法, 從而實(shí)現(xiàn)更多的功能.
在項(xiàng)目中建立Extensions文件夾, 在其中創(chuàng)建SpanExtensions.cs文件.源代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace System.Web.Mvc { public static class SpanExtensions { public static string Span(this HtmlHelper helper,string id, string text) { return String.Format(@"<span id=""{0}"">{1}</span>", id, text); } } }上面的代碼我們?yōu)镠tmlHelper類添加了一個(gè)Span()方法, 能夠返回一個(gè)Span的完整HTML字符串.
因?yàn)槊臻g是System.Web.Mvc,所以頁(yè)面使用的時(shí)候不需要再做修改,Visual Studio會(huì)自動(dòng)識(shí)別出來(lái):
請(qǐng)大家一定要注意命名空間, 如果不使用System.Web.Mvc命名空間, 那么一定要在頁(yè)面上引用你的擴(kuò)展方法所在的命名空間, 否則我們的擴(kuò)展方法將不會(huì)被識(shí)別.
接下來(lái)在頁(yè)面上可以使用我們的擴(kuò)展方法:
<div> <!-- 使用自定義的Span方法擴(kuò)展HTML Helper --> <% =Html.Span("textSpan", "使用自定義的Span方法擴(kuò)展HtmlHelper類生成的Span") %> </div>
?
(3) 使用TagBuilder類創(chuàng)建擴(kuò)展方法
上面自定義的Span()方法十分簡(jiǎn)單, 但是有時(shí)候我們要構(gòu)造具有復(fù)雜結(jié)構(gòu)的Html元素, 如果用字符串拼接的方法就有些笨拙.
ASP.NET MVC框架提供了一個(gè)幫助我們構(gòu)造Html元素的類:TagBuilder
TagBuilder類有如下方法幫助我們構(gòu)建Html控件字符串:
| 方法名稱 | 用途 |
| AddCssClass() | 添加class=””屬性 |
| GenerateId() | 添加Id,? 會(huì)將Id名稱中的"."替換為IdAttributeDotReplacement 屬性值的字符.默認(rèn)替換成"_" |
| MergeAttribute() | 添加一個(gè)屬性,有多種重載方法. |
| SetInnerText() | 設(shè)置標(biāo)簽內(nèi)容, 如果標(biāo)簽中沒(méi)有再嵌套標(biāo)簽,則與設(shè)置InnerHTML 屬性獲得的效果相同. |
| ToString() | 輸出Html標(biāo)簽的字符串, 帶有一個(gè)參數(shù)的重載可以設(shè)置標(biāo)簽的輸出形式為以下枚舉值:
|
同時(shí)一個(gè)TagBuilder還有下列關(guān)鍵屬性:
| 屬性名稱 | 用途 |
| Attributes | Tag的所有屬性 |
| IdAttributeDotReplacement | 添加Id時(shí)替換"."的目標(biāo)字符 |
| InnerHTML | Tag的內(nèi)部HTML內(nèi)容 |
| TagName | Html標(biāo)簽名, TagBuilder只有帶一個(gè)參數(shù)-TagName的構(gòu)造函數(shù).所以TagName是必填屬性 |
下面在添加一個(gè)自定義的HtmlHelper類擴(kuò)展方法,同樣是輸出一個(gè)<Span>標(biāo)簽:
在頁(yè)面上,調(diào)用這個(gè)方法:
<% =Html.Span("span.test", "使用TagBuilder幫助構(gòu)建擴(kuò)展方法", "ColorRed", new { style="font-size:15px;" })%>
生成的Html代碼為:
<span id="span-test" class="ColorRed" style="font-size: 15px;">使用TagBuilder幫助構(gòu)建擴(kuò)展方法</span>
注意已經(jīng)將id中的"."替換為了"-"字符.
五.總結(jié)
本來(lái)打算在本文中直接將ViewEngine的使用也加進(jìn)來(lái), 但是感覺(jué)本文已經(jīng)寫(xiě)了很長(zhǎng)的內(nèi)容, (雖然不多,但是很長(zhǎng)......)所以將ViewEngine作為下一章單獨(dú)介紹.
前些天 Scott Guthrie's的博客上放出了"ASP.NET MVC免費(fèi)教程", 里面介紹了創(chuàng)建一名為"NerdDinner"項(xiàng)目的全過(guò)程, 使用LINQ+ASP.NET MVC, 但是其中對(duì)于技術(shù)細(xì)節(jié)沒(méi)有詳細(xì)介紹(和本系列文章比較一下就能明顯感覺(jué)出來(lái)), 下面提供本書(shū)的pdf文件下載地址以及源代碼下載地址:
免費(fèi)下載PDF版本下載應(yīng)用源碼 + 單元測(cè)試
?
源代碼是英文版本,? 其實(shí)我最近有做一個(gè)中文的"Nerd Dinner"的想法, 但是因?yàn)橐獙?xiě)文章而且還要工作已經(jīng)讓我焦頭爛額, 寫(xiě)文章真的是一件體力活.如果有人同樣有興趣翻譯代碼, 我可以提供域名和服務(wù)器空間.
?
轉(zhuǎn)載于:https://www.cnblogs.com/jams742003/archive/2009/11/04/1595932.html
總結(jié)
以上是生活随笔為你收集整理的(四) View/Model 全解(mvc)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ext js gridpanel绑定到动
- 下一篇: s3c2440移植MQTT