当前位置:首页 > 从零开始学习ASP.NET MVC:View/Model 全解(四)

从零开始学习ASP.NET MVC:View/Model 全解(四)

点击次数:1853  更新日期:2010-12-31
\n

一.摘要


\n

本文讲解在Action中向View传递Model的几种方式.以及View获取Model以后如何编写显示逻辑.还详细的介绍了ASP.NET MVC框架提供的Html Helper类的使用及如何为Html Helper类添加自定义扩展方法.


\n

二.承上启下


\n

上一篇文章中我们学习了Controller处理一次请求的全过程.在Controller的Action中, 会传递数据给View,还会通知View对象开始显示.所以Model是在Action中获取的, 并由Action传递给View. View对象接到Action通知后会使用自己的显示逻辑展示页面.


\n

image


\n

下面首先让我们学习如何将Model传递给View对象.


\n

三.传递数据给View


\n

在MVC中,Model对象是指包含了数据的模型. Controller将Model传递给View以后, View对象中不应该做任何的业务逻辑处理, 仅仅根据Model对象做一些显示逻辑的处理.


\n

传递Model对象时, 我们有两种选择:


\n

1.传递一个弱类型的集合, 即成员为object类型的集合, 在View中需要将每个成员转换成我们需要的类型,比如int, string,自定义类型等.


\n

2.传递强类型对象, 这些类型是我们自定义的. 在View中直接使用我们传递的强类型对象, 不需要再转换类型.


\n

如果让我们自己设计一个MVC框架, 我们也会想到上面两种实现方式,接下来看看在ASP.NET MVC中的实现.


\n

1.传递弱类型的集合


\n

(1) 如何传递


\n

ASP.NET MVC框架定义了ViewContext类, 直译后是”View上下文”, 其中保存和View有关的所有数据, 其中Model对象也封装在了此类型中.


\n

ViewContext对象包含三个属性:


\n

    \n
  • IView View
    \n
  • ViewDataDictionary ViewData
    \n
  • TempDataDictionary TempData

\n

其中ViewData集合和TempData集合都是用来保存Model对象的.在一个Controller的Action中, 我们可以用如下方式为这两个集合赋值:

        /// <summary>
\n /// 传递弱类型Model的Action示例
\n /// </summary>
\n /// <returns>ViewResult</returns>
\n public ActionResult WeakTypedDemo()
\n {
\n ViewData["model"] = “Weak Type Data in ViewData”;
\n TempData["model"] = “Weak Type Data in TempData”;
\n return View(“WeakTypedDemo”);
\n }

\n

在页面中, 是用如下方式使用这两个集合:

    <div>
\n <% = ViewData["model"] %><br />
\n <% = TempData["model"] %><br />
\n </div>

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

(2) 传递过程


\n

请注意Action中的赋值语句实际上操作的是Controller类的ViewData和TempData属性, 此时并没有任何的数据传递.上一篇文章中我们已经学到, return View语句会返回一个ViewResult对象, 并且接下来要执行ViewResult的Executeresult方法. Controller的View方法会将Controller类的ViewData和TempData属性值传递给ViewResult,代码如下:

        protected internal virtual ViewResult View(IView view, object model) {
\n if (model != null) {
\n ViewData.Model = model;
\n }

\n

return new ViewResult {
\n View = view,
\n ViewData = ViewData,
\n TempData = TempData
\n };
\n }.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }
\n


\n

然后在ViewResult中根据ViewData和TempData构建ViewContext对象:

        public override void ExecuteResult(ControllerContext context) {
\n //…
\n ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
\n View.Render(viewContext, context.HttpContext.Response.Output);
\n //…
\n }

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

ViewContext对象最终会传递给ViewPage, 也就是说ViewData和TempData集合传递到了ViewPage. 我这里简化了最后的传递流程, 实际上ViewData对象并不是通过ViewContext传递到ViewPage中的, ViewPage上的ViewData是一个单独的属性, 并没有像TempData一样其实访问的是ViewContext.TempData. 这么做容易产生奇异, 本类ViewContext是一个很好理解职责十分清晰的类. 作为使用者的我们暂时可以忽略这点不足, 因为如此实现ViewData完全是为了下面使用强类型对象.


\n

(3)ViewData和TempData的区别


\n

虽然ViewData和TempData都可以传递弱类型数据,但是两者的使用是有区别的:


\n

    \n
  • ViewData的生命周期和View相同, 只对当前View有效.
    \n
  • TempData保存在Session中, Controller每次执行请求的时候会从Session中获取TempData并删除Session, 获取完TempData数据后虽然保存在内部的字典对象中,但是TempData集合的每个条目访问一次后就从字典表中删除. 也就是说TempData的数据至多只能经过一次Controller传递, 并且每个元素至多只能访问一次.

\n

2.传递强类型对象


\n

我在系统中建立了一个模型类:StrongTypedDemoDTO


\n

从名字可以看出, 这个模型类是数据传输时使用的(Data Transfer Object).而且是我为一个View单独创建的.


\n

添加一个传递强类型Model的Action,使用如下代码:

        public ActionResult StrongTypedDemo()
\n {
\n StrongTypedDemoDTO model = new StrongTypedDemoDTO() { UserName=”ziqiu.zhang”, UserPassword=”123456″ };
\n return View(model);
\n }

\n

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }
\n使用了Controller.View()方法的一个重载, 将model对象传递给View对象.下面省略此对象的传输过程, 先让我们来看看如何在View中使用此对象.


\n

在创建一个View时, 会弹出下面的弹出框:


\n

image


\n

勾选”Create a strongly-typed view”即表示要创建一个强类型的View, 在”View data class”中选择我们的数据模型类.


\n

在”view content”中如下选项:


\n

image


\n

这里是选择我们的View的”模板”, 不同的模板会生成不同的View页面代码. 虽然这些代码不一定满足我们需要, 但是有时候的确能节省一些时间,尤其是在写文章做Demo的时候. 比如我们的View是添加数据使用的,那就选择”Create”.如果是显示一条数据用的, 就选择”Detail”.


\n

以选择Detail为例, 自动生成了下列代码:

<%@ Page Language=”C#” Inherits=”System.Web.Mvc.ViewPage<DemoRC.Models.DTO.TransferModelController.StrongTypedDemoDTO>” %>
\n…
\n<body>
\n <fieldset>
\n <legend>Fields</legend>
\n <p>
\n UserName:
\n <%= Html.Encode(Model.UserName) %>
\n </p>
\n <p>
\n UserPassword:
\n <%= Html.Encode(Model.UserPassword) %>
\n </p>
\n </fieldset>
\n <p>
\n <%=Html.ActionLink(“Edit”, “Edit”, new { /* id=Model.PrimaryKey */ }) %> |
\n <%=Html.ActionLink(“Back to List”, “Index”) %>
\n </p>
\n</body>
\n…

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

页面的Model属性就是一个强类型对象, 在这里就是StrongTypedDemoDTO类实例.page页面指令可以看出, 这里的页面继承自ViewPage<T>类, 而不是ViewPage, 用T已经确定为StrongTypedDemoDTO类型, 所以Model的类型就是StrongTypedDemoDTO.


\n

3.传递数据的思考


\n

使用强类型数据要优于弱类型数据, 老赵也曾提出过. 强类型有太多的好处, 智能提示, 语意明确, 提高性能,编译时发现错误等等.


\n

所以在实际应用中, 我们应该传递强类型的数据.


\n

目前ASP.NET MVC还存在一些不足. 将页面类型化, 导致了只能传递一种数据类型实例到页面上. 而且内部代码的实现上并不十分完美.尤其是虽然我们已经知道传递的是StrongTypedDemoDTO类型, 页面的Model属性也是StrongTypedDemoDTO类型, 但是仍然要经过装箱和拆箱操作. 原因是Controller的View(object model)方法重载接收的是一个object类型.


\n

还有, 为每个View建立一个模型类, 也是一件繁琐的工作. 也许我们的业务模型中的两个类组合在一起就是View页面需要的数据, 但是却不得不建立一个类将其封装起来.模型类的膨胀也是需要控制一个事情. 尤其是对于互谅网应用而非企业内部的系统, 页面往往会有成百上千个.而且复用较少.


\n

当然目前来说既然要使用强类型的Model, 我提出一些组织Model类型的实践方法.下面是我项目中的Model类型组织结构:


\n

image


\n

这里Model是一个文件夹, 稍大一些的系统可以建立一个Model项目. 另外我们需要建立一个DTO文件夹, 用来区分Model的类型. MVC中的Model应该对应DTO文件夹中的类.在DTO中按照Controller再建立文件夹, 因为Action和View大部分都是按照Controller组织的, 所以Model也应该按照Controller组织.


\n

在Controller文件夹里放置具体的Model类. 其实两个Controller文件夹中可以同相同的类名称, 我们通过命名空间区分同名的Model类:

namespace DemoRC.Models.DTO.TransferModelController
\n{
\n /// <summary>
\n /// Action为StrongTypedDemo的数据传输模型
\n /// </summary>
\n public class StrongTypedDemoDTO
\n {
\n /// <summary>
\n /// 用户名
\n /// </summary>
\n public string UserName
\n {
\n get;
\n set;
\n }

\n

/// <summary>
\n /// 用户密码
\n /// </summary>
\n public string UserPassword
\n {
\n get;
\n set;
\n }
\n }
\n}


\n

使用时也要通过带有Controller的命名空间使用比如DTO.TransferModelController.StrongTypedDemoDTO, 或者建立一些自己的约定.


\n

四.使用Model输出页面


\n

View对象获取了Model以后, 我们可以通过两种方式使用数据:


\n

1.使用内嵌代码


\n

熟悉ASP,PHP等页面语言的人都会很熟悉这种直接在页面上书写代码的方式.但是在View中应该只书写和显示逻辑有关的代码,而不要增加任何的业务逻辑代码.


\n

假设我们创建了下面这个Action,为ViewData添加了三条记录:

        /// <summary>
\n /// Action示例:使用内嵌代码输出ViewData
\n /// </summary>
\n /// <returns></returns>
\n public ActionResult ShowModelWithInsideCodeDemo()
\n {
\n ViewData["k1"] = @”<script type=”"text/javascript”">”;
\n ViewData["k2"] = @”alert(“”Hello ASP.NET MVC !”");”;
\n ViewData["k3"] = @”</script>”;
\n return View(“ShowModelWithInsideCode”);
\n }

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

\n

\n

在ShowModelWithInsideCode中, 我们可以通过内嵌代码的方式, 遍历ViewData集合:

<html xmlns=”http://www.w3.org/1999/xhtml” >
\n<head runat=”server”>
\n <title>使用内嵌代码输出ViewData</title>
\n <% foreach(KeyValuePair<string, object> item in ViewData )
\n {%>
\n <% = item.Value %>
\n <% } %>
\n</head>
\n<body>
\n <div>

\n

<div>此页面运行的脚本代码为:</div>
\n <fieldset>
\n <% foreach(KeyValuePair<string, object> item in ViewData )
\n {%>
\n <% = Html.Encode(item.Value) %> <br />
\n <% } %>
\n </fieldset>
\n </div>
\n</body>
\n</html>


\n

页面上遍历了两遍ViewData,第一次是作为脚本输出的, 第二次由于进行了HTML编码,所以将作为文字显示在页面上.


\n

使用这种方式, 我们可以美工做好的HTML页面的动态部分, 使用<% %>的形式转化为编码区域, 通过程序控制输出.由于只剩下显示逻辑要处理,所以这种开发方式往往要比CodeBehind的编码方式更有效率, 维护起来一目了然.


\n

最让我高兴是使用这种方式后,我们终于可以只使用HTML控件了.虽然ASP.NET WebFrom编程模型中自带了很多服务器控件, 功能很好很强大, 但是那终究是别人开发的控件, 这些控件是可以随意变化的, 而且实现原理也对使用者封闭. 使用原始的页面模型和HTML控件将使我们真正的做程序的主人.而且不会因为明天服务器控件换了个用法就要更新知识, 要知道几乎所有的HTML控件几乎是被所有浏览器支持且不会轻易改变的.


\n

2.使用服务器控件


\n

注意虽然我们同样可以在ASP.NET MVC中使用服务器端控件, 但是在MVC中这并不是一个好的使用方式.建议不要使用.


\n

要使用服务器端控件, 我们就需要在后台代码中为控件绑定数据. ASP.NET MVC框架提供的添加一个View对象的方法已经不能创建后台代码, 也就是说已经摒弃了这种方式.但是我们仍然可以自己添加.


\n

首先创建一个带有后台代码的(.cs文件),一般的Web Form页面(aspx页面),然后修改页面的继承关系, 改为继承自ViewPage:

public partial class ShowModelWithControl : System.Web.Mvc.ViewPage

\n

在页面上放置一个Repeater控件用来显示数据:

<body>
\n <form id=”form1″ runat=”server”>
\n <div>
\n <asp:Repeater ID=”rptView” runat=”server”>
\n <ItemTemplate>
\n <%# ((KeyValuePair<string, object>)Container.DataItem).Value %><br />
\n </ItemTemplate>
\n </asp:Repeater>
\n </div>
\n </form>
\n</body>

\n

在Page_Load方法中, 为Repeater绑定数据:

    public partial class ShowModelWithControl : System.Web.Mvc.ViewPage
\n {
\n protected void Page_Load(object sender, EventArgs e)
\n {
\n rptView.DataSource = ViewData;
\n rptView.DataBind();
\n }
\n }

\n

在Controller中创建Action, 为ViewData赋值:

        /// <summary>
\n /// Action示例:使用服务器控件输出ViewData
\n /// </summary>
\n /// <returns></returns>
\n public ActionResult ShowModelWithControlDemo()
\n {
\n ViewData["k1"] = @”This”;
\n ViewData["k2"] = @”is”;
\n ViewData["k3"] = @”a”;
\n ViewData["k4"] = @”page”;
\n return View(“ShowModelWithControl”);
\n }

\n

运行结果:


\n

image


\n

再次强调, 在ASP.NET MVC中我们应该尽量避免使用这种方式.


\n

3.使用 HTML Helper 类生成HTML控件


\n

HTML Helper类是ASP.NET MVC框架中提供的生成HTML控件代码的类. 本质上与第一种方式一样, 只是我们可以不必手工书写HTML代码,而是借助HTML Helper类中的方法帮助我们生成HTML控件代码.


\n

同时,我们也可以使用扩展方法为HTML Helper类添加自定义的生成控件的方法.


\n

HTML Helper类的大部分方法都是返回一个HTML控件的完整字符串, 所以可以直接在需要调用的地方使用<% =Html.ActionLink() %>的形式输出字符串.


\n

(1)ASP.NET MVC中的HtmlHelper类


\n

在ViewPage中提供了Html属性, 这就是一个HtmlHelper类的实例. ASP.NET MVC框架自带了下面这些方法:


\n

    \n
  • Html.ActionLink()
    \n
  • Html.BeginForm()
    \n
  • Html.CheckBox()
    \n
  • Html.DropDownList()
    \n
  • Html.EndForm()
    \n
  • Html.Hidden()
    \n
  • Html.ListBox()
    \n
  • Html.Password()
    \n
  • Html.RadioButton()
    \n
  • Html.TextArea()
    \n
  • Html.TextBox()

\n

上面列举的常用的HtmlHelper类的方法,并不是完整列表.


\n

下面的例子演示如何使用HtmlHelper类:

    <div>
\n <% using (Html.BeginForm())
\n { %>
\n <label style=”width:60px;display:inline-block;”>用户名:</label>
\n <% =Html.TextBox(“UserName”, “ziqiu.zhang”, new { style=”width:200px;” })%>
\n <br /><br />
\n <label style=”width:60px;display:inline-block;”>密码:</label>
\n <% =Html.Password(“Psssword”, “123456″, new { style = “width:200px;” })%>
\n <% }%>
\n </div>

\n

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }
\n上面的代码使用Html.BeginForm输出一个表单对象, 并在表单对象中添加了两个Input, 一个使用Html.TextBox输出, 另一个使用Html.Password输出,区别是Html.Password输出的input控件的type类型为password.效果如图:


\n

image


\n

(2)扩展Html Helper类


\n

我们可以自己扩展HtmlHelper类, 为HtmlHelper类添加新的扩展方法, 从而实现更多的功能.


\n

在项目中建立Extensions文件夹, 在其中创建SpanExtensions.cs文件.源代码如下:

using System;
\nusing System.Collections.Generic;
\nusing System.Linq;
\nusing System.Web;
\nusing System.Web.Mvc;

\n

namespace System.Web.Mvc
\n{
\n public static class SpanExtensions
\n {
\n public static string Span(this HtmlHelper helper,string id, string text)
\n {
\n return String.Format(@”<span id=”"{0}”">{1}</span>”, id, text);
\n }
\n }
\n}


\n

上面的代码我们为HtmlHelper类添加了一个Span()方法, 能够返回一个Span的完整HTML字符串.


\n

因为命名空间是System.Web.Mvc,所以页面使用的时候不需要再做修改,Visual Studio会自动识别出来:


\n

image


\n

请大家一定要注意命名空间, 如果不使用System.Web.Mvc命名空间, 那么一定要在页面上引用你的扩展方法所在的命名空间, 否则我们的扩展方法将不会被识别.


\n

接下来在页面上可以使用我们的扩展方法:

    <div>
\n <!– 使用自定义的Span方法扩展HTML Helper –>
\n <% =Html.Span(“textSpan”, “使用自定义的Span方法扩展HtmlHelper类生成的Span”) %>
\n </div>

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

(3) 使用TagBuilder类创建扩展方法


\n

上面自定义的Span()方法十分简单, 但是有时候我们要构造具有复杂结构的Html元素, 如果用字符串拼接的方法就有些笨拙.


\n

ASP.NET MVC框架提供了一个帮助我们构造Html元素的类:TagBuilder


\n

TagBuilder类有如下方法帮助我们构建Html控件字符串:


\n

\n


\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
方法名称用途
AddCssClass()添加class=””属性
GenerateId()添加Id, 会将Id名称中的”.”替换为IdAttributeDotReplacement 属性值的字符.默认替换成”_”
MergeAttribute()添加一个属性,有多种重载方法.
SetInnerText() 设置标签内容, 如果标签中没有再嵌套标签,则与设置InnerHTML 属性获得的效果相同.
ToString() 输出Html标签的字符串, 带有一个参数的重载可以设置标签的输出形式为以下枚举值:
\n

    \n
  • TagRenderMode.Normal — 有开始和结束标签
    \n
  • TagRenderMode.StartTag — 只有开始标签
    \n
  • TagRenderMode.EndTag — 只有结尾标签
    \n
  • TagRenderMode.SelfClosing — 单标签形式,如<br/>

\n

同时一个TagBuilder还有下列关键属性:


\n

\n


\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
属性名称用途
Attributes Tag的所有属性
IdAttributeDotReplacement 添加Id时替换”.”的目标字符
InnerHTML Tag的内部HTML内容
TagName Html标签名, TagBuilder只有带一个参数-TagName的构造函数.所以TagName是必填属性

\n


下面在添加一个自定义的HtmlHelper类扩展方法,同样是输出一个<Span>标签:

        public static string Span(this HtmlHelper helper, string id, string text, string css, object htmlAttributes)
\n {
\n //创意某一个Tag的TagBuilder
\n var builder = new TagBuilder(“span”);

\n

//创建Id,注意要先设置IdAttributeDotReplacement属性后再执行GenerateId方法.
\n builder.IdAttributeDotReplacement = “-”;
\n builder.GenerateId(id);

\n

//添加属性
\n builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));

\n

//添加样式
\n builder.AddCssClass(css);
\n //或者用下面这句的形式也可以: builder.MergeAttribute(“class”, css);

\n

//添加内容,以下两种方式均可
\n //builder.InnerHtml = text;
\n builder.SetInnerText(text);

\n

//输出控件
\n return builder.ToString(TagRenderMode.Normal);

\n

}

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n

在页面上,调用这个方法:

<% =Html.Span(“span.test”, “使用TagBuilder帮助构建扩展方法”, “ColorRed”, new { style=”font-size:15px;” })%>

\n

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }
\n


\n

生成的Html代码为:

<span id=”span-test” class=”ColorRed” style=”font-size: 15px;”>使用TagBuilder帮助构建扩展方法</span>

\n

.csharpcode, .csharpcode pre
\n{
\n font-size: small;
\n color: black;
\n font-family: consolas, “Courier New”, courier, monospace;
\n background-color: #ffffff;
\n /*white-space: pre;*/
\n}
\n.csharpcode pre { margin: 0em; }
\n.csharpcode .rem { color: #008000; }
\n.csharpcode .kwrd { color: #0000ff; }
\n.csharpcode .str { color: #006080; }
\n.csharpcode .op { color: #0000c0; }
\n.csharpcode .preproc { color: #cc6633; }
\n.csharpcode .asp { background-color: #ffff00; }
\n.csharpcode .html { color: #800000; }
\n.csharpcode .attr { color: #ff0000; }
\n.csharpcode .alt
\n{
\n background-color: #f4f4f4;
\n width: 100%;
\n margin: 0em;
\n}
\n.csharpcode .lnum { color: #606060; }

\n


注意已经将id中的”.”替换为了”-”字符.


\n

五.总结


\n

本来打算在本文中直接将ViewEngine的使用也加进来, 但是感觉本文已经写了很长的内容, (虽然不多,但是很长……)所以将ViewEngine作为下一章单独介绍.


\n

前些天 Scott Guthrie’s的博客上放出了”ASP.NET MVC免费教程”, 里面介绍了创建一名为”NerdDinner”项目的全过程, 使用LINQ+ASP.NET MVC, 但是其中对于技术细节没有详细介绍(和本系列文章比较一下就能明显感觉出来), 下面提供本书的pdf文件下载地址以及源代码下载地址:


\n

image


\n
  • 免费下载PDF版本
    \n
  • 下载应用源码 + 单元测试

    \n

    源代码是英文版本, 其实我最近有做一个中文的”Nerd Dinner”的想法, 但是因为要写文章而且还要工作已经让我焦头烂额, 写文章真的是一件体力活.如果有人同样有兴趣翻译代码, 我可以提供域名和服务器空间.


    \n

    差点提供忘记本篇文章的示例源代码下载:


    \n

    http://files.cnblogs.com/zhangziqiu/AspNet-Mvc-4-Demo.rar

    来源:http://www.cnblogs.com/zhangziqiu/

    上一篇:从零开始学习ASP.NET MVC:Controller/Action 深入解析与应用实例(三)

  • \n