您是第 Web Page Tracking 位访客

水~墨~

昂首阔步,不留一点遗憾!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

模型元数据ModelMetaData是MVC中很重要的概念,它包括但不仅限于 模型的类型,模型包含了哪些属性,属性都是什么类型的,属性上都有什么特性。

ASP.NET MVC3.0 提供了默认的模型元数据 DataAnnotationsModelMetadata 继承自ModelMetadata(另外系统提供了默认的模型元数据提供器DataAnnotationsModelMetadataProvider)

public class DataAnnotationsModelMetadata : ModelMetadata

它的构造函数如下

public DataAnnotationsModelMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Func modelAccessor, Type modelType, string propertyName, DisplayColumnAttribute displayColumnAttribute);

 

 

DataAnnotationsModelMetadata类有常用的几个属性

DisplayName 显示名称,DisplayFormatString格式字符串

TemplateHint 获取一个值选择使用哪个模版

 

对于DisplayName ,LabelFor<TModel, TValue> 方法中使用此属性来生成标签文本.  意思就是一旦我们的model上有定义了DispalyName特性,那么view中使用html.editForModel()方法就会自动为model的这个属性显示出label标签"  <label for="username">名称</label></

  

[Display( Name="名称",Order=2)]   //order属性改变在html页面中的排列顺序
  public string username { get; set; }

 

image

html源代码:

<div class="editor-label"><label for="username">名称</label></div>

<div class="editor-field"><input class="text-box single-line" data-val="true" data-val-maxwords="名称 has too many words" data-val-maxwords-wordcount="2" data-val-required="名称 字段是必需的。" id="username" name="username" type="text" value=""> <span class="field-validation-valid" data-valmsg-for="username" data-valmsg-replace="true"></span></div>

 

属性username上用的Display特性就是System.ComponentModel.DataAnnotations.DisplayAttribute类提供一个通用特性,使您可以为实体分部类的类型和成员指定可本地化的字符串

 

另外还有一些特性来自System.Web.MVC 和 System.ComponentModel.DataAnnotations,名称凡类似 XXXXAttribute的都为特性类,都有特定的使用范围,有的限制模型属性,有的限制Contrller,有的限制Action等等。

 

 

 

下面列举了这2个命名空间下,内置的而且常用的特性类

1)System.Web.MVC空间下的

AcceptVerbsAttributeActionFilterAttributeActionNameAttributeAsyncTimeoutAttributeAuthorizeAttributeBindAttribute

HiddenInputAttribute 

ActionFilterAttribute  表示所有操作-筛选器特性的基类

HttpDeleteAttribute 类,表示一个特性,该特性用于限制操作方法,以便该方法仅处理 HTTP DELETE 请求

HttpGetAttributeHttpPostAttribute 表示特性,用于限制操作方法,仅限处理PUT请求

HttpPutAttribute  表示一个特性,该特性用于限制操作方法,以便该方法仅处理 HTTP PUT 请求。

 

例:ActionNameAttribute 指定action的实际actionname,用法如下

[ActionName()]

public ActionResult  Index()

 

例:HiddenInputAttribute类,表示一个特性,该特性用于指示是否应将属性值或字段值呈现为隐藏 input 元素

[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Property, AllowMultiple = false, Inherited = true)]

public sealed class HiddenInputAttribute : Attribute

[HiddenInput]
public string zhanshi { get; set; }  //只隐藏了Input,但是label还是显示了zhanshi

[HiddenInput(DisplayValue=false)]   //只生了 input hidden  zhanshi2 没显示
public string zhanshi2 { get; set; }

image

当DisplayValue设置为false时候,只为zhangshi2属性生成了一个 <input type=”hidden”   name=”zhangshi2”  value>元素。但是zhangshi生成了2个元素,一个displayName元素,照常显示,而input元素则隐藏了。

 

2)System.ComponentModel.DataAnnotations 空间下的特性类

AssociationAttribute  指定某个实体成员表示某种数据关系,如外键关系。

DataTypeAttribute 指定要与数据字段关联的附加类型的名称。   为属性呈现html时候才有用,数据验证的时候不使用这个,你懂的。

DisplayColumnAttribute    将所引用的表中显示的列指定为外键列。
DisplayFormatAttribute    指定 ASP.NET 动态数据如何显示数据字段以及如何设置数据字段的格式。
EditableAttribute    指示数据字段是否可编辑。
EnumDataTypeAttribute    使 .NET Framework 枚举能够映射到数据列。
FilterUIHintAttribute    表示一个特性,该特性用于指定列的筛选行为。
KeyAttribute    表示一个或多个用于唯一标识实体的属性。
MetadataTypeAttribute    指定要与数据模型类关联的元数据类。
RangeAttribute    指定数据字段值的数值范围约束。
RegularExpressionAttribute    指定 ASP.NET 动态数据中的数据字段值必须与指定的正则表达式匹配。
RequiredAttribute    指定需要数据字段值。
ScaffoldColumnAttribute    指定类或数据列是否使用基架。
ScaffoldTableAttribute    指定类或数据表是否使用基架。
StringLengthAttribute    指定数据字段中允许的最小和最大字符长度。
TimestampAttribute    将列的数据类型指定为行版本。
UIHintAttribute    指定动态数据用来显示数据字段的模板或用户控件。
ValidationAttribute    作为所有验证特性的基类。

下面例子针对DataTypeAttribute进行应用

[DataType(DataType.EmailAddress)] //表是货币值
       [Display(Order=1)] //html显示的顺序
       public string lastname { get; set; }

view:@Html.DisplayForModel()

呈现出的html代码和外观:image 点击邮箱名称就可以直接调用默认操作系统的邮件系统。

<div class="display-field"><a href="mailto:sdfsd@sina.com">sdfsd@sina.com</a></div>,即使model中lastname设置成不正确的email格式,也会展现出。

image html代码:<a href="mailto:sdfsd">sdfsd</a>

 

Date    表示日期值。
Time    表示时间值。
Duration    表示对象存在的一段连续时间。
PhoneNumber    表示电话号码值。
Currency    表示货币值。
Text    表示所显示的文本。
Html    表示一个 HTML 文件。
MultilineText    表示多行文本。
EmailAddress    表示电子邮件地址。
Password    表示密码值。
Url    表示 URL 值。
ImageUrl    表示图像的 URL。

注意DataType不能重复对同一个属性使用

例子:  

[DataType(DataType.DateTime)] //表是货币值
[Display(Order=1)]
public string lastname { get; set; }

lastname设置为 DateTime.Now.ToLongDateString()  =2014年4月1日

image

如何lastname能转换为DateTime就转换,不能转换就按照原来的显示。

 

 

 

上面就是常用的特性,有些特性是用来辅助将属性或者元素呈现出来,有些还带有验证功能。

 

 

 

 

 

 

自定义模版,比如自定义控件,当某个属性拥有了[UIHint("模版名称")]特性,那么就会按照新的方式展示,不会按照默认的方式执行。

例:model:public string name{get;set;}  

view:@html.DisplayforModel()

image

最终为属性name呈现的html元素为input输入框,这个input输入框就是默认的模版,当知道是string或者Int类型后,再没设置其他模版的前提下,选择默认的input元素。

 

如果我不想让对string类型,在呈现的时候显示input输入框元素,那么我们可以自定义模版,然后在属性上应用[UIHint(自定义的新模版)]就可以不使用默认的input元素了。

现在开始动手,假设将string类型的属性呈现出另外的效果,比如display时候显示 2个输入,编辑时候显示2个输入框。

 

先新建2个文件夹,注意文件夹名称必须是分别为DisplayTemplates,EditorTemplates

image 

然后在文件夹里建立2个相同名称的view视图 Data.cshtml。Data就是新定义的模版名称。

代码分别如下

DisplayTemplates/Data.cshtml

<script type="text/javascript">
    $(function () {
        $(".datepicker").datepicker({ "dateFormat": "yy-mm-dd" })
    });
</script>
@Html.TextBox("", String.Format("{0:yyyy-MM-dd}"
, ViewData.TemplateInfo.FormattedModelValue), new { @class = "datepicker" })

EditTemplates/Data.cshtml

@Html.DropDownList("",MvcApplication1.Sample_ModelMeta.DropDownListMenu.年齡選項(),"请选择年龄")

 

model中设置模版

public class user
{
[UIHint("Data")]
 public string lastname { get; set; }
}

view: 第一个是编辑,第2个是展示

 @Html.DisplayFor(model=>model.lastname,"Data")
 @Html.EditorFor(model=>model.lastname,"Data")

action中设置lastname=DateTime.Now

html代码:

<div>
   
显示:<input id="lastname" name="lastname" type="text" value="2014/4/2">
<script type="text/javascript">
    $(function () {
        $(".datepicker").datepicker({ "dateFormat": "yy-mm-dd" })
    });
</script>
编辑:<input class="datepicker hasDatepicker" id="lastname" name="lastname" type="text" value="2014/4/2">
   
   
    </div>

效果图: 使用EditorFor呈现的是一个输入框,当你点击后可以选择时间。这个时间控件是Jquery Ui中的,所以view要引用jquery.ui.cs

image

 

MVC查找模版的路径先为当前controller同名的view文件夹下查找,找不到了,再最后是shared文件夹中查找,如果没找到任何模版,则还是按照默认显示)

 

 

 

 

 

元数据定制,就是在属性上添加自定义特性,可以设置元数据。 例如 自定义[displayText]特性

至于如何自定义,首先我们要查看系统默认存在的一些特性的类的结构

  public class DisplayTextAttribute:Attribute,IMetadataAware

 

继承Attribute类和IMetadataAware接口,实现接口中的OnMetadatAware接口

 public void OnMetadataCreated(ModelMetadata metadata)
        {
            this.DisplayName=this.DisplayName??(metadata.PropertyName??metadata.ModelType.Name);
             if(null==this.ResourceType)
             {
                 metadata.DisplayName=this.DisplayName;
                 return ;
             }
      
       PropertyInfo property=this.ResourceType.GetProperty(this.DisplayName, BindingFlags.NonPublic|BindingFlags.Public| BindingFlags.Static);
             //PropertyInfo property = metadata.ModelType.GetProperty(this.DisplayName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
       metadata.DisplayName = "我把所有列名都改了";//property.GetValue(null, null).ToString();
       metadata.TemplateHint="MultilineText";
        }

在方法中,我们可以设置模型元数据的信息 ,比如此处我将DisplayName都设置成了“xxx”,并设置了模版 为MultilineText。

[DisplayText]
public string Name { get; set; }

效果展示:@html.displayForModel()   为Name呈现一个 label内容为“我把所有列名都改了”,而且输入框显示的是多行模式。

 

 

 

 

元数据提供系统,ASP.net提供了一个可插拔的模型元数据提供系统DataAnAnnotationModelMetaProvder,可插拔的意思就是可以自定义然后替换掉默认的元数据提供系统。

若要自定义,请继承ModelMetadataProvider类,实现3个方法。

 

下面是部分自定义元数据提供系统CustomerMetaProvider类

 

namespace MvcApplication1.CustomerMetaProvider
{
    public class CustomerMetadataProvider : ModelMetadataProvider
    {
        public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
        {
            throw new NotImplementedException();
        }
        public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
        {
            throw new NotImplementedException();
        }
        public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
        {
            throw new NotImplementedException();
        }
    }
    public class Contact
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string EmailAddress { get; set; }
    }
}

 

应用上面的提供系统,要在Global.asax.cs   的Application_Start中加上一句  ModelMetadataProviders.Current = new CustomModelMetadataProviderWithConfig();

这样就要MVC项目中当模型绑定和为属性呈现元素时候都要从上面自定义的元数据提供系统提供ModelMetaData,所以上面的3个方法一定要重写。

本例子没实现这3个方法,待补充!

 

 

 

 

至此,模型元数据的意义,模型元数据定制,自定义模型元数据提供系统,以及自定义html模版 都研究完成。

再加上签名的 模型绑定器,自定义验证特性,自定义验证特性的客户端验证都已完成。

目前还剩下 自定义值提供器 和 自定义视图模版和视图结构。

posted on 2014-04-02 14:24  水墨.MR.H  阅读(3533)  评论(0编辑  收藏  举报
知识共享许可协议
本博客为水墨原创,基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的水墨(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。