码迷,mamicode.com
首页 > Web开发 > 详细

ASP.NET MVC Model元数据及其定制: Model元数据的定制(原版没分段,分开自己看)

时间:2017-09-06 18:26:17      阅读:305      评论:0      收藏:0      [点我收藏+]

标签:mat   virtual   efault   label   containe   目标   present   ret   tip   

转自:http://www.cnblogs.com/artech/archive/2012/04/12/model-metadata-02.html 

 

 在《上篇》我们已经提到过了,Model元数据的定制是通过在作为Model的数据类型极其属性成员上应用相应的特性来实现,这些用于声明式元数据定义的特性大都定义在System.ComponentModel.DataAnnotations.dll程序集中,程序集的名称同时也是对应的命名空间名称,所以我们可以它们为数据注解特性(Data Annotation Attribute),接下来我们来介绍一些常用的数据注解特性,以及它们对于元数据具有怎样的影响。[本文已经同步到《How ASP.NET MVC Works?》中]

 

目录

一、UIHintAttribute

二、HiddenInputAttribute与ScaffoldColumnAttribute

三、DataTypeAttribute与DisplayFormatAttribute

四、EditableAttribute与ReadOnlyAttribute

五、DisplayAttribute与DisplayNameAttribute

六、RequiredAttribute 

 

 一、UIHintAttribute

  HtmlHelper和HtmlHelper<TModel>定义了一系列的基于Model的模板方法,比如Display/DisplayFor、Editor/EditorFor、DisplayForModel/EditForModel、Lable/LabelFor和DisplayText/DisplayTextFor。所谓模板方法,就是说我们在通过调用这些方法将代表Model的数据呈现在View中的时候,并不对最终呈现的UI元素进行显式地控制,而采用默认或者指定的模板来决定最终呈现在浏览器中的HTML。每个具体的模板均具有相应的名称,这些模板方法在进行Model呈现的时候根据对应的Model元数据得到对应的模板名称。具体来说,模板的名称通过ModelMetadata的TemplateHint属性表示,如下面的代码片断所示,这是一个字符串类型的可读写属性。

1: public class ModelMetadata 
2: { 
3:   //其他成员
4:   public virtual string TemplateHint{get;set;} 
5: }
 

   ModelMetadata的TemplateHint属性可以通过UIHintAttribute特性来定制。如下面的代码片断所示,UIHintAttribute具有PresentationLayer和UIHint两个只读属性,分别用于限制展现层的类型(比如“HTML”、“Silverlight”、“WPF”、“WinForms”等和模板名称,这两个属性均在构造函数中初始化。

 1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=true)] 
 2: public class UIHintAttribute : Attribute 
 3: { 
 4:   //其他成员 
 5:   public UIHintAttribute(string uiHint); 
 6:   public UIHintAttribute(string uiHint, string presentationLayer); 7: 
 8:   public string PresentationLayer { get; } 
 9:   public string UIHint { get; } 
 10: }

  通过应用在UIHintAttribute上的AttributeUsageAttribute定义我们不难看出,由于其AllowMultiple属性被设置为True,意味着我们可以在相同的目标元素上应用多个UIHintAttribute特性,那么哪一个会被选择用于定制Model元数据呢? 如果多个UIHintAttribute应用到了相应的元素(类型或者属性),会先选择一个PresentationLayer属性为“MVC”(不区分大小写)的UIHintAttribute。如果这样的UIHintAttribute不存在,则选择一个PresentationLayer属性值为空的UIHintAttribute。值得一提的是,如果具有多个匹配的UIHintAttribute可控选择,系统会选择第一个,但是通过反射获取到的Attribute的顺序和Attribute被标注的属性没有直接的关系。

  接下来我们通过一个简单的实例来演示UIHintAttribute特性对Model元数据的影响,以及对应用在相同目标元素上的多个UIHintAttribute的选择策略。考虑到重用性,我们编写了如下一个静态辅助方法GetModelMetadata<TModel>用于获取Model类型为TModel针对指定属性的Model元数据。

1: public static ModelMetadata GetModelMetadata<TModel>(string propertyName) 
2: { 
3:   ModelMetadataProvider provider = ModelMetadataProviders.Current; 
4:   ModelMetadata containerMetadata = new ModelMetadata(provider, null, () => null, typeof(TModel), null); 
5:   return containerMetadata.Properties.FirstOrDefault(m => m.PropertyName == propertyName); 
6: }

  我们通过如下的代码定义了一个类型为Model的数据类型,三个属性Foo、Bar和Baz定义其中。对于属性Bar来说,我们同时应用了两个模板名称分别为“Template A”和“Template B”的UIHintAttribute特性,后者将字符“Mvc”作为presentationLayer参数的值。属性Baz通用应用了基于模板名称“Template A”的UIHintAttribute特性。

1: public class Model 
2: { 
3:   public string Foo { get; set; } 
4:  
5:    [UIHint("Template A")] 
6:   [UIHint("Template B", "Mvc")] 
7:   public string Bar { get; set; } 
8:  
9:   [UIHint("Template A")] 
10:  public string Baz { get; set; } 
11: }

  现在我们在一个控制台程序中编写如下的测试程序。我们通过上面定义的辅助方法GetModelMetadata<TModel>创建针对定义在数据类型Model中的Foo、Bar和Baz三个属性的ModelMetadata,并分别打印出对应的TemplateHint属性。

1: ModelMetadata foo = GetModelMetadata<Model>("Foo"); 
2: ModelMetadata bar = GetModelMetadata<Model>("Bar"); 
3: ModelMetadata baz = GetModelMetadata<Model>("Baz"); 
4:  
5: Console.WriteLine("Foo: {0}", foo.TemplateHint??"N/A"); 
6: Console.WriteLine("Bar: {0}", bar.TemplateHint ?? "N/A"); 
7: Console.WriteLine("Baz: {0}", baz.TemplateHint ?? "N/A"); 

  上面的测试程序执行之后会在控制台上产生如下的输出结果,这和我们上面介绍的关于UIHintAttribute特性针对Model元数据的定制,以及针对应用在相同目标元素上的多个UIHintAttribute特性的选择策略是相符的。

1: Foo: N/A 2: Bar: Template B 3: Baz: Template A

 

二、HiddenInputAttribute与ScaffoldColumnAttribute

  一个作为Model的数据类型往往具有一个唯一标识,当我们以编辑模式将Model对象在View中呈现的时候,往往不允许用于对作为唯一标识的属性进行修改。如果ID不具有可读性(比如是一个随机数或者GUID),有时候甚至不希望让它显示在界面上。这个时候我们就会使用到特性HiddenInputAttribute。 HiddenInputAttribute并没有定义在System.ComponentModel.DataAnnotations命名空间下,它的命名空间为System.Web.Mvc,所以该特使是专门为ASP.NET MVC设计的。顾名思义,HiddenInputAttribute会将目标对象以类型为hidden的<input/>元素呈现出来。在默认的情况下,应用了HiddenInputAttribute特性的目标对象依然会以只读的形式显示出来。如果不希望显示,可以将如下所示的布尔类型的DisplayValue设置为False(默认值为False)。

1: [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple=false, Inherited=true)] 
2: public sealed class HiddenInputAttribute : Attribute 
3: { 
4:   public HiddenInputAttribute(); 
5:   public bool DisplayValue { get;set; } 
6: }

同样以前面定义的Model类型为例,现在我们将HiddenInputAttribute特性应用在属性Foo和Bar上,后者将DisplayValue设置为False。

1: public class Model 
2: { 
3:   [HiddenInput] 
4:   public string Foo { get; set; } 
5:  
6:   [HiddenInput(DisplayValue = false)] 
7:   public string Bar { get; set; } 
8:  
9:   public string Baz { get; set; } 
10: }

  现在我们通过调用HtmlHelper<TModel>的扩展方法EditForModel方法将一个具体的Model对象(new Model { Foo = "foo", Bar = "bar", Baz = "baz" })显示在某个基于Model类型的强类型View中。

  最终呈现出来的效果如下图所示,我们可以看到针对应用了HiddenInputAttribute的两个属性Foo和Bar,前者以只读的形式显示出来;后者却在界面上看不到。 如下所示的用于呈现Foo、Bar和Baz三个属性对应的HTML,从中我们可以清楚地看到两个应用了HiddenInputAttribute的属性,不论其DisplayValue属性具有怎样的值,均对应着一个的类型为hidden的<input>元素。

1: <div class="editor-label">
    <label for="Foo">Foo</label></div> 
2:   <div class="editor-field">foo<input id="Foo" name="Foo" type="hidden" value="foo" /> ... 
3: </div> 
4:  
5: <input id="Bar" name="Bar" type="hidden" value="bar" />
6:  
7: <div class="editor-label">
    <label for="Baz">Baz</label></div>
8: <div class="editor-field"> 9: <input class="text-box single-line" id="Baz" name="Baz" type="text" value="baz" />... 10: </span> 11: </div>

  HiddenInputAttribute针对Model元数据的定制体现ModelMetadata的如下两个属性的上,其中一个就是上面介绍的TemplateHint,另一个则是布尔类型的属性HideSurroundingHtml,表示目标元数是否需要通过相应的HTML呈现在UI界面上。具体来说,针对应用了HiddenInputAttribute的目标元素对应的ModelMetadata对象,其被设置为“HiddenInput”,并将其DisplayValue属性为HideSurroundingHtml属性赋值。“HiddenInput”为ASP.NET MVC自身定义的一个默认模板名称,也就是说当目标元素应用了HiddenInputAttribute特性,这个默认模板别用来实现对其的UI呈现。

1: public class ModelMetadata 
2: { 
3:  //其他成员 
4:  public virtual string TemplateHint{get;set;} 
5:  public virtual bool HideSurroundingHtml { get; set; } 
6: }

  我们同样通过一个测试程序来验证HiddenInputAttribute特性对Model元素据的定制。针对上面定义的Model类型(Foo和Bar属性应用了HiddenInputAttribute特性),我们通过如下的测试程序将基于Foo、Bar和Baz属性的三个ModelMetadata对象获取出来,然后分别打印出它们的TemplateHint和HideSurroundingHtml属性。

1: ModelMetadata foo = GetModelMetadata<Model>("Foo"); 
2: ModelMetadata bar = GetModelMetadata<Model>("Bar"); 
3: ModelMetadata baz = GetModelMetadata<Model>("Baz"); 
4:  
5: Console.WriteLine("{0,-5}{1, -14}{2, -20}", "", "TemplateHint", "HideSurroundingHtml"); 
6: Console.WriteLine(new string(-, 40)); 
7:  
8: Console.WriteLine("{0,-5}{1, -14}{2, -20}", "Foo", foo.TemplateHint ?? "N/A", foo.HideSurroundingHtml); 
9: Console.WriteLine("{0,-5}{1, -14}{2, -20}", "Bar", bar.TemplateHint ?? "N/A", bar.HideSurroundingHtml); 
10: Console.WriteLine("{0,-5}{1, -14}{2, -20}", "Baz", baz.TemplateHint ?? "N/A", baz.HideSurroundingHtml);

  上面的程序运行之后会在控制台上产生如下的输出结果,这和我们前面的介绍是相匹配的。 1:  TemplateHint HideSurroundingHtml 2: ---------------------------------------- 3: Foo HiddenInput False 4: Bar HiddenInput True 5: Baz N/A False 

  有的读者可能会问这样一个问题,UIHintAttribute和HiddenInputAttribute都会设置表示Model元数据的ModelMetadata对象的TemplateHint属性,如果两个特性均应用到相同的目标元素上,最终生成的ModelMetadata对象具有怎样的TemplateHint属性值呢?答案是:UIHintAttribute具有更高的优先级。 对于应用了HiddenInputAttribute特性目标元素,不论其DisplayValue具有怎样的值,都会出现在通过模板方法生成的HTML中,如果我们希望将它从HTML中移除,我们可以应用另一个叫作ScaffoldColumnAttribute的特性。我们将通过预定义模板自动生成HTML的方式成为“基架(Scaffolding)”,ScaffoldColumnAttribute中的ScaffoldColumn代表存在于“基架”中并最终呈现在HTML中的字典,而该特性本身则用于控制目标元素是否应该存在于基架之中。如下面的代码片断所示,ScaffoldColumnAttribute具有一个布尔类型的只读属性Scaffold表示目标元素是否应该存在于呈现在最终生成的HTML的基架中,该属性在构造函数中初始化。

1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false)] 
2: public class ScaffoldColumnAttribute : Attribute 
3: { 
4:   public ScaffoldColumnAttribute(bool scaffold); 
5:   public bool Scaffold { get; } 
6: }

  ScaffoldColumnAttribute最终用于控制用于表示针对目标对象的ModelMetadata对象的ShowForDisplay和ShowForEdit属性。如下面的代码所示,这是两个布尔类型的属性,分别表示目标元素是否应该出现在显示和编辑模式的基架中。如果ShowForDisplay的属性为False,在调用模板方法EditorFor/EditorForModel方法时目标元素将不会出现在最终生成的HTML中;同理,在通过DisplayFor/DisplayForModel方法生成的HTML将不会包含ShowForDisplay为False的元素。这两个属性值在默认情况下均为True。

1: public class ModelMetadata 
2: { 
3:   //其他成员 
4:   public virtual bool ShowForDisplay { get; set; } 
5:   public virtual bool ShowForEdit { get; set; } 
6: } 

三、DataTypeAttribute与DisplayFormatAttribute

ASP.NET MVC Model元数据及其定制: Model元数据的定制(原版没分段,分开自己看)

标签:mat   virtual   efault   label   containe   目标   present   ret   tip   

原文地址:http://www.cnblogs.com/zyblogs/p/7485314.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!