http://www.cnblogs.com/lzhp/archive/2013/03/25/2981650.html

Mvc model系列文章主要分为三部分:Model Templates,Model Binding,Model Validation。本篇文章主要内容包括下面三个部分:

A.使用模板视图助手

B.自定义视图模板系统

C.理解元数据提供体系

一、使用模板视图助手

1.1助手体验

  模板视图助手,我理解为MVC提供的根据model中定义的数据类型,来生成视图(View)标签的助手。显而易见其好处,当我们更改model中的数据类型时,不用担心要更改view。下面我们就来体验一下吧。

先建立一个空的mvc解决方案,起名为ModelTemplate,如下图

然后在models中新建一个类,在此只是为了演示,所以没有把下面三个类分开

    //定义人员类

    public  class Person

    {

        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

    }

然后在controllers中添加个HomeControl,在Index中添加下面的代码:

            Person myPerson = new Person

            {

                PersonId = 1,

                FirstName = "李",

                LastName = "占朋",

                BirthDate = DateTime.Parse("1988-1-15"),

                HomeAddress = new Address

                {

                    Line1 = "仓山区",

                    Line2 = "南后街",

                    City = "福州",

                    Country = "中国",

                    PostalCode = "350000"

                },

                IsApproved = true,

                Role = Role.User

            };

            return View(myPerson);

接着生成一下解决方案,在Index上面右击,添加一个视图:

在视图中添加下面的代码,并运行

<h4>人员</h4>

<div class="field">

<label>姓名:</label>

@Html.EditorFor(x => x.FirstName)

@Html.EditorFor(x => x.LastName)

</div>

<div class="field">

<label>是否通知:</label>

@Html.EditorFor(x => x.IsApproved)

</div>

运行结果为:

会发现mvc framework为我们根据我们定义的数据类型生成了input和checkbox。当我们将IsApproved改为字符串,运行结果为:

不用更改前端,同样模板视图助手会根据类型去生成input。这样模板视图助手是不是很好用呢?除了可以生成input还可以生成其他的,如果我们想让前端显示的是只读的话,可以使用:@Html.DisplayFor(x=>x.IsApproved)。运行结果为:

除了可以使用强类型的,还可以使用下面的用法,后面直接跟出字段的字符串:@Html.DisplayText("IsApproved"),这样的结果和上面的一致。

除了上面的@Html.DisplayFor(x=>x.IsApproved),Html.EditorFor(x =>x.FirstName),还有Html.Display("FirstName"),,Html.Label("FirstName"),Html.LabelFor(x=> x.FirstName),Html.DisplayText("FirstName"),  Html.DisplayTextFor(x =>x.FirstName)可以使用。如果想了解个清楚的话,可以自行尝试。建议大家都使用强类型的表示,可以减少错误。注意上面生成的源文件对应的html:

1.2支架模板

我们已经体验了模板助手的快感,下面就会有个问题,既然他会根据类型来判断要生成的字段,如果我们想看到所有的字段,是不是要一个个打出来呢?肯定可以有更简洁的方法,那就是我们要看的一个支架模板,支架模板有三个DisplayForModel,EditorForModel,LabelForModel。如果我们想显示上面的所有字段,我们就是用一个EditorForModel试试。为了看到生成的checkbox,我把IsApproved还改为布尔型。

是不是比我们原来的方法要快捷呢?快的同时,细心的你肯定会发现上面的问题

A.时间字段变长了,
B.地址字段没有显示出来
C.还显示出了用户ID,通常情况我们不想让用户看到这个东西的

如果你是追求完美的人,那么你一定会先想到

D.显示的lable标签是英文的,我想看到的是中文的

看来支架模板不怎么理想啊,出现了这么多问题。下面我们就来一一解决上面出现的问题。解决问题之前,我们先来引入一个名词,元数据(Metadata)在此你就把他看做描述字段的一些标签吧。然后我们就一一的解决问题

A问题的解决办法就是使用        

[DataType(DataType.Date)]

public DateTime BirthDate { get; set; }

在DataType上面按F12,会发现其实一个枚举类型,具体的作用可以看其摘要。还可以设置为其他的类型。在此不一一的说明。

B:问题的解决办法:先分析一下为什么不能显示出地址,因为地址的类型是一个类,不是简单类型,所以我们的Framework为了尊重这个类,没有推断出来其字段的类型,所以只有使用前面的@Html.EditorFor(m=>m.HomeAddress),我们列出address的字段时,才可以去推断。

C:问题有两种解决方法,一种是单纯的为了显示,不用把Id以hidden标签来呈现在html中,一种要对其操作,比如说修改了,我们通常使用id作为标识符,只是把其隐藏起来。

下面分别给出两种解决方法:

1、[ScaffoldColumn(false)]//前端不会显示Hidden

public int PersonId { get; set; }

2、[HiddenInput(DisplayValue=true)]如果是true的话,前端会呈现出值和前端生成的hidden,如果是false的话,前端只生成的hidden

D的解决方法是:使用[Display(name=””)]。接下来看一下显示的结果:

对于元数据,还有个[UIHint("")]没有使用上,其作用是把原来的属性的类型按指定的类型显示,其“”里面可以是Boolean、Collection、Decimal、EmailAddress、HiddenInput、HiddenInput、MultilineText、Object、Password、String、Text、Url。其显示结果根据意思可以看出来,具体的查msdn或参考老A文章,如果不能转化的,会报错,如把一个字符串的转化成Boolean的,会提示无法转化。

除此之外,还有个较为重要的是[MetadataType(typeof(ClassName))]元数据,经常用在ORM方面,由于ORM生成的实体如果修改后,编译之后就会把修改的内容删除了,所以可以使用

这个元数据把两个类合并在一起,互相协同工作。但是前提是要声明类为partial,下面还以人员为例:

假设下面的为orm生成的类:

public partial class Person 

{

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; }

}

通过MetadataType数据源把其与PersonMetadataSource类协同工作,主要是让姓多行显示,其代码如下:

    [MetadataType(typeof(PersonMetadataSource))]

    public partial class Person

    {

    }

    public partial class PersonMetadataSource

    {

        [UIHint("MultilineText")]

        public string FirstName { get; set; }

    }

其效果图为:

对于其他两个支架模板用法相似,在此不再赘述。

二、自定义视图模板系统

2.1自定义模板的举例

  有时,我们想让指定值显示为自己想要的效果,那么我们应该可以使用自定义视图模板。比如用户角色想出现一个ddl的效果,当然可以使用Html.DropDownListFor,还有另外一种方法是在~/Views/Shared 文件夹新建一个文件EditorTemplates,里面添加一个视图,但是这个是分部视图。如图所示:

注意视图名称一定要和前面要展示的类型相一致,这里是和Role保持一致,因为到时间显示的时间,文件名(类型名)是要作为查找的参数。不一致的话,是查找不到的。把下面的代码贴到刚才创建的文件中:

@using ModelTemplate.Models

@model Role

<select id="Role" name="Role">

    @foreach (Role value in Enum.GetValues(typeof(Role))) {

    <option value="@value" @(Model == value ? "selected=\"selected\"" : "")>@value

    </option>

    }

</select>

运行就可以看到用户角色是使用ddl来显示的了,当然还有个好处就是复用了,其他有使用到该字段的视图也会以ddl来呈现,如果只想在某个controller显示的话,可以使用/Views/<controller>/EditorTemplates,该路径是一个指定的路径,不可以改变的,不能把EditorTemplate改为其他的字母。

下面为用户角色显示的效果图:

2.2使用模板的顺序

善于思考的你,看到上面的例子,肯定会想为什么不使用原来的模板了呢,而使用自定义模板,那么什么时间使用内置模板呢?这里面是有个顺序的。下面稍微列出其顺序:

1.Html.EditorFor(m => m.SomeProperty,"MyTemplate")因为我们已经制定了要使用MyTemplate模板,所以排在最前面。
2.被指定了元数据的模版,如UIHint
3.被指定为元数据的数据类型关联的模版,如DataType特性
4.自定义在EditorTemplates、DisplayTemplates(和EditorTemplate类似)里面的模板
5.最后就是内置的模板
注意:上面的2和3容易弄混。一个是元数据模板,一个是元数据的数据类型。我们可以使用一个例子来说明,包装IsApproved字段。

通过UIHint和DataType以及自定义的模板,来说明,同时使用前两个的话显示的是多行,如果同时使用后两个的话,实现的是密码。其中代码如下:

        [UIHint("MultilineText")]

        [DataType(DataType.Password)]

        public bool IsApproved { get; set; }

@model bool

<select id="Role" name="Role">

    <option  value="@Model" @(Model == true ? "selected=\"selected\"" : "")>通知</option>

    <option value="@(!Model)" @(Model == false ? "selected=\"selected\"" : "")>未通知</option>

</select>

可以自行删减,来观察其效果。除了上面的情况,可能还有其他的情况,具体的遇到了再去研究。

三、理解元数据提供体系

  截止到现在,我们已经看了前面的一些例子,是什么在我们上面的例子中为我们默默的服务着呢?前面有提到过元数据,那么是谁创造的元数据呢?答案是DataAnnotationsModelMetadataProvider类。是它来检查和处理我们加载类前面的特性的,然后根据其特性来呈现在view中。可以使用F12来看其定义,会发现其实它是继承了AssociatedMetadataProvider一个抽象类,那么我们可以理解为:AssociatedMetadataProvider为元数据的使用提供了一些方法如创建元数据方法,然后DataAnnotationsModelMetadataProvider类重写了他的方法,最后一些属性或者说是特性是属于元数据的。绕了几个弯,还是使用老A的一张图比较好说明:

  看了这张图,比较激动的童鞋肯定想创建一个CustomModelMetadataProvider继承AssociatedMetadataProvider类,那么就让我们试着重写CreateMetadata方法,下面就以我IsApproved为例吧,因为翻译为通知有点不妥,我想把他改为赞同。

在项目下建立一个文件夹,然后添加一个类

代码如下:

 public class CustomModelMetadataProvider : AssociatedMetadataProvider

    {

        protected override ModelMetadata CreateMetadata(

                                            IEnumerable<Attribute> attributes,

                                            Type containerType,

                                            Func<object> modelAccessor,

                                            Type modelType,

                                            string propertyName)

        {

            //ModelMetadata metadata = base.CreateMetadata(attributes, containerType, modelAccessor,

            //modelType, propertyName);

            ModelMetadata metadata =new ModelMetadata (this, containerType, modelAccessor,

            modelType, propertyName);

            if (propertyName != null && propertyName.Equals("IsApproved"))

            {

                metadata.DisplayName = "赞同";

            }

            return metadata;

        }

    }

最后在global文件中Application_Start()添加初始化代码:

ModelMetadataProviders.Current = new CustomModelMetadataProvider();

  发现显示的lable已经改过来了,但是其他添加的元数据不起作用了。如果想让它起作用的话,肯定是要继承DataAnnotationsModelMetadataProvider,然后要实现父类的方法,最后在添加自己的功能,这样就可以看到我们想要的效果了。代码如下:

protected override ModelMetadata CreateMetadata(

                                            IEnumerable<Attribute> attributes,

                                            Type containerType,

                                            Func<object> modelAccessor,

                                            Type modelType,

                                            string propertyName)

        {

            ModelMetadata metadata = base.CreateMetadata(attributes, containerType, modelAccessor,

            modelType, propertyName);

            //ModelMetadata metadata =new ModelMetadata (this, containerType, modelAccessor,

            //modelType, propertyName);

            if (propertyName != null && propertyName.Equals("IsApproved"))

            {

                metadata.DisplayName = "赞同";

            }

            return metadata;

        }

运行的时间,我们可以在创建元数据的时间设置断点看看各个参数的含义,以更好的理解该类和方法。准备收工了,其他的方法就不在此一一实现。

四、总结:

  本文通过简单的实例,来引出了模板助手,再实现了自定义模板,最终说明了模型模板的实现原理。文中可能有些名词叫的不是很准确,一方面是因为自己的E文不好,另一个方面是为了更好的理解,如果有不足的地方请大牛们多多指点。附上文中的代码:源码。该代码使用vs2010编写。

五、参考文献:

1、《pro asp.net mvc3 framework》

2、http://home.cnblogs.com/u/mszhangxuefei/

3、http://www.cnblogs.com/artech/

ASP.NET MVC —— Model之一模型模板的更多相关文章

  1. ASP.NET MVC学习之模型模板篇

    一.前言 如果你使用ASP.NET MVC制作后台一定会爱上它的EditorForModal.DisplayForModal和LabelForModal方法,因为这些方法可以将模型直接变成对应的标签, ...

  2. ASP.NET MVC Model之二模型绑定

    Asp.net mvc中的模型绑定,或许大家经常用,但是具体说他是怎么一回事,可能还是会有些陌生,那么,本文就带你理解模型绑定.为了理解模型绑定,本文会先给出其定义,然后对通过比,来得出使用模型绑定的 ...

  3. ASP.NET MVC Model元数据(五)

    ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...

  4. ASP.NET MVC Model元数据(四)

    ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...

  5. ASP.NET MVC Model元数据(三)

    ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...

  6. ASP.NET MVC Model元数据(二)

    ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...

  7. ASP.NET MVC Model元数据(一)

    ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退 ...

  8. ASP.NET MVC Model元数据

    ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...

  9. ASP.NET MVC Model验证(四)

    ASP.NET MVC Model验证(四) 前言 本篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而Mod ...

随机推荐

  1. 20155306 白皎 免考实践总结——0day漏洞

    本次免考实践提纲及链接 第一部分 基础知识 1.1 0day漏洞概述 1.2二进制文件概述 1.3 必备工具 1.4 crack实验 第二部分 漏洞利用 2.1栈溢出利用 2.1.1 系统栈工作原理 ...

  2. 带Alpha通道的色彩叠加问题

    css3的rgba色彩模式.png/gif图片的alpha通道.canvas的rgba色彩模式.css3的阴影.css3的opacity属性等等,这些应用在网页中,有意无意间,我们的页面多了许多半透明 ...

  3. sql——sql中的各种连接

    现有两张表 tablea 和 tableb     各种连接 1.笛尔卡积 SELECT * FROM TabA a,TabB b where a.id = b.id /*笛尔卡积乘积*/ 返回的结果 ...

  4. FIFO IP核

    转载: 说白了,IP核就是别人做好了的硬件模块,提供完整的用户接口和说明文档,更复杂的还有示例工程,你只要能用好这个IP核,设计已经完成一半了.说起来容易,从冗长的英文文档和网上各个非标准教程中汲取所 ...

  5. Github pages + Minimal-Mistakes + Disqus建立个人博客记录

    本文详细记录了利用Github pages建立个人博客的步骤. github pages官方推荐使用Jekyll生成静态网页,jekyll支持各种不同的主题,Minimal-Mistakes是一个功能 ...

  6. 科普贴 | 数字钱包MetaMask安装使用详解,活用MetaMask轻松驾驭以太坊

    MetaMask 是一款浏览器插件钱包,不需下载安装客户端,只需添加至浏览器扩展程序即可使用,非常方便.它是很多支持 ETH 参投的 ICO 项目推荐使用的钱包之一. 2018年初最火的一个币,应该就 ...

  7. HashMap相关总结

    1.HashMap:根据键值hashCode值存储数据,大多数情况下可以直接定位到它的值,但是遍历顺序不确定.所有哈希值相同的值存储到同一个链表中                         Ha ...

  8. time since epoch

    C++11 提供了新的获取系统时间的库函数,在获取时间的时候一般常用的是获取time since epoch,下面来看一下如何获取这个时间. #include <iostream> #in ...

  9. 手写vue双向绑定数据

    来一张原理图: 实现思路: (1)绑定data 种的数据,为每个数据添加指令.通过Object,defineProperty() 来通知属性是否更改 (2) 找到每个DOM节点的指令.绑定事件.并绑定 ...

  10. 如何判断可见字符 Unicode

    一个Unicode字符串,如何判断其中都是可见字符? //根据国标 GB2312 的中文汉字及符号 区位码的范围判断 Function CheckIsGB2312(Char : WideChar) : ...