- Model 元数据是针对数据类型的一种描述信息,主要用于控制数据类型本身及其成员属性在界面上的呈现方式,同时也为Model 绑定和验证提供必不可少的元数据信息。一个复杂数据类型通过属性的方式定义了一系列的数据成员,而Model 元数据不仅仅是数据类型本身的描述,对数据成员的描述也包含其中,所以Model 元数据具有一个层次化结构。
- AdditionalMetadataAttribute定义的值放在元数据的AdditionalValues中.实现接口IMetadat aAware
- ModelMetadata包含几个重要的属性ModelType,IsComplexType,IsNullableValueType,ContainerType,PropertyName,Model
- IsComplexType
判断某个类型是否是复杂类型的条件只有一个,即是否允许字符串类型向该类型的转换。所以所有的基元类型C Primative Type) 和可空值类型CNullable Type) 均不是复杂类型。对于一个默认为复杂类型的自定义数据类型,可以在它上面应用TypeConverterAttribute 特性并指定一个支持字符串转换的TypeConverter 类型,使之转变成简单类型。 - UIHintAttribute
ModelMetadata 的TemplateHint 属性可以通过UIHintAttribute 特性来定制.指定要使用的模板. (UIHintImplementation).多个的时候,要区分优先级. - HiddenInputAttribute
HiddenInputAttribute 特性Mode lMetadata 对象的TemplateHint 属性设置为"HiddenI nput",其HideSurroundingHtrnl 属性则对应着HiddenInpu tAttribute 的DisplayValue 属性。UIHintAttribute 具有更高的优先级。 - ScaffoldColumnAttribute
具有一个布尔类型的只读属性Scaffold表示目标元素是否应该存在于呈现在最终生成的HTML 的基架中,HiddenInputAttribute 是隐藏的,但是包含在HTML中.ScaffoldColumnAttribute 最终用于控制ModelMetadata 的ShowForDisplay 和ShowForEdit属性
- Data TypeAttribute控制显示格式,如Email.DisplayFormatAttribute
其中DataTypeAttribute 中设置的数据类型对应于ModelMetadata 的DataTypeName属性,而DisplayF ormatAttribute 的ConvertEmp可S位ingToNull 和NullDisplayText 属性对应着ModelMetadata 的同名属性。DataTypeAttribute可以继承自定义格式
- EditableAttribute ReadOnlyAttribute
- Display DisplayNameAttribute
- RequiredAttribute
- IMetadataAware,通过实现此接口可以实现对元数据的定制,接口中只有一个方法 void OnMetadataCreated(ModelMetadata metadata);
- 当Model 元数据被创建出来后,上述的这一系列数据注解特性会被提取出来对其进行初始化,然后获取应用在目标元素上所有实现了IMetadataAware 接口的特性,并将初始化的ModelMetadata 对象作为参数调用OnMetadataCreated 方法。通过自定义实现该接口的特性不仅仅可以添加一些额外的元数据属性,还可以修改己经通过相应的标注特性初始化的相关属性。
- ModelMetadata 的RequestValidationEnabled 属性开启/关闭请求验证的开关。该属性在默认情况下为True ,意味着默认开启针对HTI\在L 标记的请求验证。
- AllowHtmlAttribute metadata.RequestValidationEnabled = false;
- 自定义的控件模板要放在Share下或者Controller对应的View中的EditorTemplates文件夹下.可以理解为,一般的页面也是对应的Model的模板页,两者之间的实现思路是一样的.
@model bool <table> <tr> <td>@Html.RadioButton("", true, Model)</td> <td>@Html.RadioButton("", false, Model)</td> </tr> </table>
- MVC内部定义了很多模板,当调用HtmlHelper.For的时候,会根据显示模式或者编辑模式和元数据找到一个显示用的模板.
- MVC预定义的模板:EmailAddress,Hiddenlnput,HTML,(Text,String效果一样),URL,MultilineText,Password,decimal,Boolean,Collection,Object
- 模板查找路径顺序
- 传入的TemplateName
- ModelMetadata的TemplateHint属性
- DataTypeName属性
- 非空类型(不是Nullable类型)用类型名作为模板View名称Nullable类型的获取真实类型作为View名称,如Int?的模板为Int32的View
- 非复杂类型,会选择String的模板,然后退出检索,否则下一步
- 如果声明是接口,
- 如果继承IEnumerable采用Collection模板
- 选择Object模板
- ,然后退出检索,否则下一步
- 向父类追溯,选择各级父类的名称作为模板
- 直到Object类型,如果实现Ienumerable,则选择Collection代替Object.
- 查找的源代码
internal static IEnumerable<string> GetViewNames(ModelMetadata metadata, params string[] templateHints) { foreach (string templateHint in templateHints.Where(s => !String.IsNullOrEmpty(s))) { yield return templateHint; } // We don‘t want to search for Nullable<T>, we want to search for T (which should handle both T and Nullable<T>) Type fieldType = Nullable.GetUnderlyingType(metadata.RealModelType) ?? metadata.RealModelType; // TODO: Make better string names for generic types yield return fieldType.Name; if (!metadata.IsComplexType) { yield return "String"; } else if (fieldType.IsInterface) { if (typeof(IEnumerable).IsAssignableFrom(fieldType)) { yield return "Collection"; } yield return "Object"; } else { bool isEnumerable = typeof(IEnumerable).IsAssignableFrom(fieldType); while (true) { fieldType = fieldType.BaseType; if (fieldType == null) { break; } if (isEnumerable && fieldType == typeof(Object)) { yield return "Collection"; } yield return fieldType.Name; } } }
- 优先使用自定义的模板,路径是"DisplayTemplate/{TemplateName}"和"EditorTemplate/{TemplateName}",找不到的时候在默认的模板中查找
- 系统默认的模板
- 编辑系统模板
private static readonly Dictionary<string, Func<HtmlHelper, string>> _defaultEditorActions = new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) { { "HiddenInput", DefaultEditorTemplates.HiddenInputTemplate }, { "MultilineText", DefaultEditorTemplates.MultilineTextTemplate }, { "Password", DefaultEditorTemplates.PasswordTemplate }, { "Text", DefaultEditorTemplates.StringTemplate }, { "Collection", DefaultEditorTemplates.CollectionTemplate }, { "PhoneNumber", DefaultEditorTemplates.PhoneNumberInputTemplate }, { "Url", DefaultEditorTemplates.UrlInputTemplate }, { "EmailAddress", DefaultEditorTemplates.EmailAddressInputTemplate }, { "DateTime", DefaultEditorTemplates.DateTimeInputTemplate }, { "Date", DefaultEditorTemplates.DateInputTemplate }, { "Time", DefaultEditorTemplates.TimeInputTemplate }, { typeof(byte).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(sbyte).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(int).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(uint).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(long).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(ulong).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(bool).Name, DefaultEditorTemplates.BooleanTemplate }, { typeof(decimal).Name, DefaultEditorTemplates.DecimalTemplate }, { typeof(string).Name, DefaultEditorTemplates.StringTemplate }, { typeof(object).Name, DefaultEditorTemplates.ObjectTemplate }, };
- 编辑系统模板
- 显示系统模板
private static readonly Dictionary<string, Func<HtmlHelper, string>> _defaultDisplayActions = new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) { { "EmailAddress", DefaultDisplayTemplates.EmailAddressTemplate }, { "HiddenInput", DefaultDisplayTemplates.HiddenInputTemplate }, { "Html", DefaultDisplayTemplates.HtmlTemplate }, { "Text", DefaultDisplayTemplates.StringTemplate }, { "Url", DefaultDisplayTemplates.UrlTemplate }, { "Collection", DefaultDisplayTemplates.CollectionTemplate }, { typeof(bool).Name, DefaultDisplayTemplates.BooleanTemplate }, { typeof(decimal).Name, DefaultDisplayTemplates.DecimalTemplate }, { typeof(string).Name, DefaultDisplayTemplates.StringTemplate }, { typeof(object).Name, DefaultDisplayTemplates.ObjectTemplate }, };
- 自定义模板查找路径
private static readonly Dictionary<DataBoundControlMode, string> _modeViewPaths = new Dictionary<DataBoundControlMode, string> { { DataBoundControlMode.ReadOnly, "DisplayTemplates" }, { DataBoundControlMode.Edit, "EditorTemplates" } };
protected virtual ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor) { IEnumerable<Attribute> attributes = FilterAttributes(containerType, propertyDescriptor, propertyDescriptor.Attributes.Cast<Attribute>()); ModelMetadata result = CreateMetadata(attributes, containerType, modelAccessor, propertyDescriptor.PropertyType, propertyDescriptor.Name); ApplyMetadataAwareAttributes(attributes, result); return result; }
时间: 2024-10-17 20:40:29