010_模板辅助器方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了010_模板辅助器方法相关的知识,希望对你有一定的参考价值。

         相比辅助器方法,模板辅助器方法更智能一些,它们可以指定想要显示的属性,而让MVC框架去判断应该使用什么样的html元素。只是,需要一些初期关注才能建立起来,但毕竟是一种显示数据的更为灵活的方式。

         这里打算继续使用介绍辅助器方法时使用的项目,但是,CreatePerson.cshtml视图在之前的辅助器方法会在生成的HTML元素上添加data属性,来支持表单验证,这一点在后面对模板辅助器方法的使用时打算禁用,但是,客户端验证特性对程序的其他部分仍然有效,调整后的代码如下(粗体部分为修改的内容):

@model HelperMethods.Models.Person

@{
    ViewBag.Title = "CreatePerson";
    Html.EnableClientValidation(false);
}

<h2>CreatePerson</h2>

@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post,
 new { @class = "personClass", data_formType = "person" })) 
{
    <div class="dataElem">
        <label>PersonId</label>
        @Html.TextBoxFor(m => m.PersonId)
    </div>
    <div class="dataElem">
        <label>First Name</label>
        @Html.TextBoxFor(m => m.FirstName)
    </div>
    <div class="dataElem">
        <label>Last Name</label>
        @Html.TextBoxFor(m => m.LastName)
    </div>
    <div class="dataElem">
        <label>Role</label>
        @Html.DropDownListFor(m => m.Role, new SelectList(Enum.GetNames(typeof(HelperMethods.Models.Role))))
    </div>
    <input type="submit" value="提交" />
}

 

 

使用模板辅助器方法

         首先来看看编辑元素的辅助器方法:Html.EditorFor和Html.Editor。Editor方法的字符串参数是用来指定编辑器元素所需的属性的。EditorFor是强类型的辅助器方法,可以使用lambda表达式指定编辑器元素所需要的模型属性。为了演示,下面同时混合使用了这两种方法,实际项目中可以根据自己的喜好使用,但是还是推荐使用EditorFor方法,这样可以避免由误输属性名造成的错误:

@model HelperMethods.Models.Person

@{
    ViewBag.Title = "CreatePerson";
    Html.EnableClientValidation(false);
}

<h2>CreatePerson</h2>

<!--使用模板辅助器方法-->
@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post, new { @class = "personClass", data_formType = "person" }))
{
    <div class="dataElem">
        <label>PersonId</label>
        @Html.Editor("PersonId")
    </div>
    <div class="dataElem">
        <label>First Name</label>
        @Html.Editor("FirstName")
    </div>
    <div class="dataElem">
        <label>Last Name</label>
        @Html.EditorFor(m => m.LastName)
    </div>
    <div class="dataElem">
        <label>Role</label>
        @Html.EditorFor(m => m.Role)
    </div>
    <div class="dataElem">
        <label>Birth Date</label>
        @Html.EditorFor(m => m.BirthDate)
    </div>
    <input type="submit" value="提交" />
}

最终效果如图,这和之前的辅助器方法实现的一样,只是增加了一个BirthDate的显示:

技术分享 

         这里的日期显示成这个样子,是因为我的浏览器的问题,默认情况下IE浏览器对日期的显示不怎么友好,如果换成其他浏览器(如Opera浏览器)就可以正常显示,当然在IE下可以通过jQuery等一些第三方的控件实现。所以在开发Web端程序的时候一定要注意不同浏览器直接的差异(对于这几个属性的显示不同的还有PersonId等)。

         HTML5规范对input元素所编辑的常规的属性类型,定义了一些不同的类型,如数字和日期,而这里的模板辅助器方法采用的就是HTML5的新类型。下面是我的浏览其中生成的HTML结果:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>CreatePerson</title>
    
    <link href="/Content/Site.css" rel="stylesheet">
    <style type="text/css">
        label {
            display: inline-block;
            width: 100px;
        }

        .dateElem {
            margin: 5px;
        }
    </style>
</head>
<body>
    

<h2>CreatePerson</h2>

<!--使用模板辅助器方法-->
<form class="personClass" action="/app/forms/Home/CreatePerson" method="post" data-formtype="person">    <div class="dataElem">
        <label>PersonId</label>
        <input name="PersonId" class="text-box single-line" id="PersonId" type="number" value="0">
    </div>
    <div class="dataElem">
        <label>First Name</label>
        <input name="FirstName" class="text-box single-line" id="FirstName" type="text" value="">
    </div>
    <div class="dataElem">
        <label>Last Name</label>
        <input name="LastName" class="text-box single-line" id="LastName" type="text" value="">
    </div>
    <div class="dataElem">
        <label>Role</label>
        <input name="Role" class="text-box single-line" id="Role" type="text" value="Admin">
    </div>
    <div class="dataElem">
        <label>Birth Date</label>
        <input name="BirthDate" class="text-box single-line" id="BirthDate" type="datetime" value="0001/1/1 0:00:00">
    </div>
    <input type="submit" value="提交">
</form>

</body>
</html>

         Type标签属性指定了input元素应当显示的类型,但是,可惜不是所有的浏览器都能支持,原因就是HTML5特性比较新。

         后面会展示如何为MVC框架提供附加信息,以便改善辅助器方法生成的HTML,下面先看看完整的辅助器集。

辅助器

示例

描述

Display

Html.Display ("FirstName")

渲染指定模型属性的只读视图,会根据该属性的类型及元数据选用一个HTML元素

DisplayFor

Html.DisplayFor(x => x.FirstName)

上一辅助器的强类型版本

Editor

Html.Editor("FirstName")

渲染指定模型属性的一个编辑器,会根据该属性的类型及元数据选用一个HTML元素

EditorFor

Html.EditorFor(x => x.FirstName)

上一辅助器的强类型版本

Label

Html.Label("FirstName")

渲染指定模型的HTML<label>元素(注意:它显示的是指定属性的属性名,而非属性值)

LabelFor

Html.LabelFor(x => x.FirstName)

上一辅助器的强类型版本

生成标签和显示元素

         后面对Home控制器做一下修改,用来演示这些辅助器方法:

using HelperMethods.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HelperMethods.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Fruits = new string[] { "Apple", "Orange", "Pear" };
            ViewBag.Cities = new string[] { "New York", "London", "Paris" };

            string message = "This is an HTML element: <input>";

            return View((object)message);
        }

        public ActionResult CreatePerson()
        {
            return View(new Person());
        }

        [HttpPost]
        public ActionResult CreatePerson(Person person)
        {
            return View("DisplayPerson", person);
        }

    }
}

 

         上面的DisplayPerson对应的视图文件添加到/Views/Home文件夹中,其内容如下:

@model HelperMethods.Models.Person

@{
    ViewBag.Title = "DisplayPerson";
}

<h2>DisplayPerson</h2>

<div class="dataElem">
    @Html.Label("PersonId")
    @Html.Display("PersonId")
</div>
<div class="dataElem">
    @Html.Label("FirstName")
    @Html.Display("FirstName")
</div>
<div class="dataElem">
    @Html.LabelFor(m => m.LastName)
    @Html.DisplayFor(m => m.LastName)
</div>
<div class="dataElem">
    @Html.LabelFor(m => m.Role)
    @Html.DisplayFor(m => m.Role)
</div>
<div class="dataElem">
    @Html.LabelFor(m => m.BirthDate)
    @Html.DisplayFor(m => m.BirthDate)
</div>

         启动程序,导航至/Home/CreatePerson后,填充内容,并点击“提交”按钮,便可看到下图的结果:

 技术分享

         下面是这些辅助器方法生成的HTML,需要注意的是,Display和DisplayFor方法默认情况下并未生成HTML元素——它们只是发布了它们所操作的属性值:

<!DOCTYPE html>
<html><head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>DisplayPerson</title>
    
    <link href="/Content/Site.css" rel="stylesheet">
    <style type="text/css">
        label {
            display: inline-block;
            width: 100px;
        }

        .dateElem {
            margin: 5px;
        }
    </style>
</head>
<body>
    

<h2>DisplayPerson</h2>

<div class="dataElem">
    <label for="PersonId">PersonId</label>
    100
</div>
<div class="dataElem">
    <label for="FirstName">FirstName</label>
    Adam
</div>
<div class="dataElem">
    <label for="LastName">LastName</label>
    Freeman
</div>
<div class="dataElem">
    <label for="Role">Role</label>
    Admin
</div>
<div class="dataElem">
    <label for="BirthDate">BirthDate</label>
    0001/1/1 0:00:00
</div>
</body></html>

         看似这些辅助器不是很有用,但可以做些调整来使其产生更希望显示给用户的输出结果。

使用整体模型模板辅助器

   前面说的都是针对单个属性的辅助器,其实还有一些针对整个对象的辅助器——这称之为支架辅助器。

辅助器

示例

描述

DisplayForModel

Html.DisplayForModel()

渲染整个模型对象的只读视图

EditorForModel

Html.EditorForModel()

渲染整个模型对象的编辑器元素

LabelForModel

Html.LabelForModel()

渲染对整个模型对象进行引用的HTML<label>元素

注:所谓模板辅助器Templated Helper)是在视图中使用的一种辅助性工具,用以为视图模型的属性生成HTML标记。模板辅助器有两大类:一类就叫模板辅助器Templated Helper),作用是在视图中为模型的个别属性生成HTML标记。另一类叫作支架辅助器Scaffolding Helper),作用是在视图中创建整个模型所有属性HTML标记。这两种模板辅助器又分别有三种:

  • 标签辅助器(LabelLabelForLabelForModel),用于生成模型属性的标签(以属性名称作为标签);
  • 显示辅助器(DisplayDisplayForDisplayForModel),用于生成模型属性的显示标记(显示属性的值,或显示只读数据);
  • 编辑辅助器(EditEditForEditForModel),用于生成对模型属性进行编辑的标记(编辑器)。

   下面演示一下通过LabelForModel和EditForModel 辅助器简化CreatePerson.cshtml视图的结果:

@model HelperMethods.Models.Person

@{
    ViewBag.Title = "CreatePerson";
    Html.EnableClientValidation(false);
}

<h2>CreatePerson: @Html.LabelForModel()</h2>

@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post, new { @class = "personClass", data_formType = "person" }))
{
    @Html.EditorForModel()

    <input type="submit" value="提交" />
}

 

         下面是效果,虽然还有些不太正确,主要是因为支架辅助器生成的HTML与前面的布局视图中CSS的定义不对应,以及它会默认显示所有的模型中的属性,后面做一些修改便可达到我们的目标:

技术分享 

         下面先通过对样式作简单的改动,对视图外观加以整理,以使它们预制件辅助器添加到div和input元素中的CSS的class值对应起来。文件_Layout.cshtml修改的结果:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="~/Content/Site.css" rel="stylesheet" />
    <style type="text/css">
        label {
            display: inline-block;
            width: 100px;
        }

        .dateElem {
            margin: 5px;
        }

        h2 > label {
            width: inherit;
        }

        .editor-label, .editor-field {
            float: left;
        }

            .editor-label, .editor-label label, .editor-field input {
                height: 20px;
            }

        .editor-label {
            clear: left;
        }

        .editor-field {
            margin-left: 10px;
            margin-top: 10px;
        }

        input[type=submit] {
            float: left;
            clear: both;
            margin-top: 10px;
        }

        .column {
            float: left;
            margin: 10px;
        }
    </style>
</head>
<body>
    @RenderBody()
</body>
</html>

 技术分享

使用模型元数据

         用前面的辅助器模板生成的HTML可以看出其并非十分智能,经常会产生不需要的HTML。但是,我们可以通过模型元数据(MetaData加以辅助,从而改善这种结果。它的实现原理是:使用C#注解属性,以及注解属性的参数值来为辅助器提供一定的指示,辅助器方法在生成HTML元素时将会根据这些信息进行组织。

用元数据控制编辑及可见性

         比如我们通过HiddenInput注解属性将Person类中的PersonId属性隐藏后,在运用这个注解属性时,Html.EditorFor和Html.EditorForModel辅助器会生成一个对应的只读视图,下面分别是代码示例和效果图:

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

namespace HelperMethods.Models
{
    public class Person
    {
        [HiddenInput]
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime BirthDate { get; set; }
        public Address HomeAddress { get; set; }
        public bool IsApproved { get; set; }
        public Role Role { get; set; }
    }

    public class Address
    {
        public string Line1 { get; set; }
        public string Line2 { get; set; }
        public string City { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
    }

    public enum Role
    {
        Admin,
        User,
        Guest
    }

}

 

技术分享技术分享

          这样得到了一个该属性值的文本显示效果,且在HTML中生成了一个字符串值和一个隐藏的input元素。如果不希望显示该属性值,可以将该注解属性的DisplayValue参数设置为false,如:

public class Person
    {
        [HiddenInput(DisplayValue = false)]
        public int PersonId { get; set; }
        …
    }
…

技术分享 

技术分享 

         此时,即便使用的是类似Html.EditorFor这样的针对某一属性的模板辅助器,任会达到上面的效果。


排除支架中的一个属性

 


 

如果不需要某一属性生成HTML元素,可以使用ScaffoldColumn(命名空间为:System.ComponentModel.DataAnnotations)注解属性。相对于HiddenInputScaffoldColumn是将某一属性标记为完全禁止,即在生成HTML的时候将不会将该属性生成对应的HTML元素,如下面示例:

         [ScaffoldColumn(false)]

        public int PersonId { get; set; }

但是,这么做也有一个问题,就是这对模型绑定是有影响的,而且对模板辅助器(相对于支架辅助器的那种)是不起作用的。

使用用于标签的元数据

         默认情况下,Label、LabelFor、LabelForModel,以及EditorForMordel辅助器会以属性名称作为它们生成的标签元素的内容,但实际项目中经常不希望这么做,尤其是在中文环境的项目中。这个时候可以使用System.ComponentModel命名空间下的DisplayName注解属性,并为其参数提供希望的值即可(同时还有System.ComponentModel.DataAnnotations中的Display注解属性)。如:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HelperMethods.Models
{
    // DisplayName 也可以用于属性,但习惯上建议在模型类上应用,而在属性上使用 Display
    [DisplayName("New Person")]
    public

以上是关于010_模板辅助器方法的主要内容,如果未能解决你的问题,请参考以下文章

009_辅助器方法

前端模板 artTemplate之辅助方法template.helper

flask模板的基本用法模板语法渲染模板模板辅助工具

solidedge st3 更换已有工程图的模板及辅助零件如何应用

如何更新 Ember 模板中辅助主体内的变量

在 Jasmine 中访问 Meteor 模板辅助函数以进行集成测试