[转载]MVC中的扩展点(十)辅助方法 – xfrog – 博客园.
MVC中的辅助方法与ASP.NET中的服务器控件类似,都是用于生成特定的HTML代码。MVC提供了三个辅助类,它们分别是:用于生成HTML元素的 HtmlHelper,用于Ajax处理的AjaxHelper,以及用于生成Url的UrlHelper。这三个辅助类通过ViewPage的 Ajax、Html、Url属性向外提供。由于视图都是是从ViewPage继承的,所以,我们在视图模板中可以直接通过这三个属性来调用辅助方法。
AjaxHelper、HtmlHelper、UrlHelper位于System.Web.Mvc命名空间中,如以下类图所示,这三个辅助类本身仅包含 了一些基本的方法和属性,而具体辅助方法的实现,MVC是采用了扩展方法的技术。如:AjaxHelper通过System.Web.Mvc.Ajax命 名空间中的AjaxExtensions静态类来实现,HtmlHelper通过System.Web.Mvc.Html命名空间中的一系列静态扩展类来 实现。
这种将具体辅助方法分离到单独命名空间的做法,有利于我们对辅助方法的扩展及替代:
1、要添加新的辅助方法,我们只 需建立自己的静态扩展类,然后在web.config配置文件中添加对扩展类所在命名空间的引 用:<pages><namespaces><add namespace=”静态扩展类所在命名空间”/></namespace></pages>
2、要替换所有默认的辅助方法,我们只需将web.config配置文件中的特定命名空间,如System.Web.Mvc.Html替换为自己的命名空间即可。
模板系统
由DisplayExtensions静态扩展类提供的Html.Display、Html.DisplayFor、 Html.DisplayForModel辅助方法用于根据模型类型自动产生显式Html代码,由EditorExtensions静态扩展类提供的 Html.Editor、Html.EditorFor、Html.EditorForModel辅助方法用于根据模型类型自动产生用于编辑的Html代 码。它们都是建立在模板基础上的:根据模型属性类型,从默认的模板集合中取出相应的模板,然后根据模板内容生产相应的Html元素。
如以下类图所示,通过一些列的特性,可控制模板系统的行为:
Html.DisplayForModel和Html.EditorForModel在产生模型的显示/编辑界面时,直接跟具模型每个属性的类型及特性定义来产生每一个属性的Html元素。我们可以通过子视图来定义特定模型的呈现方式,其具体步骤如下:
1、在工程 Views\Shared目录下创建两个新的文件夹:DisplayTemplates和EditorTemplates,其中 DisplayTemplates文件夹用于保存模型显式界面的模板(由Html.DisplayForModel辅助方法使 用),EditorTemplates文件夹用于保存模型编辑界面的模板(由Html.EditorForModel辅助方法使用)。
2、在相应文件夹下添加新的视图文件,名称必须和模型类名完全一致,勾选“创建子视图选项”。
3、与视图模板一致,可在子视图中访问ViewData及Model
当我们定义完子视图后,模板系统首先根据模型类型名在相应文件夹中查找是否有自定义的模板,如果有则使用自定义模板,没有则使用默认模板。
Mvc通过一些列特性来控制模板系统的行为,但是在有些情况下,模型源代码我们是不能修改的,比如由Linq to SQL或.NET实体框架产生的模型类,这些类由工具自动产生,我们无法直接修改源代码。幸运的是,这些自动产生的类都是定义为partial的,这样我 们可以使用System.ComponentModel.DataAnnotations命名空间下的MetadataTypeAttribute特性来 定义一个与模型相关的元数据类型,例如,Product模型类型定义如下:
namespace CnBlogs.TestModel
{
public partial class Product
{
public string Name { get; set; }
public string Description { get; set; }
}
}
.codearea { color: black; background-color: white; line-height: 18px; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,”BitStream Vera Sans Mono”,courier,monospace,serif; }.codearea pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap pre { white-space: pre-wrap; word-wrap: break-word; }.codearea pre.alt { background-color: rgb(247, 247, 255) ! important; }.codearea .lnum { color: rgb(79, 129, 189); line-height: 18px; }我们可以定义与之相关的元数据类:
namespace CnBlogs.TestModel
{
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
private class ProductMetadata
{
[DisplayName("产品名称")]
public string Name { get; set; }
[DisplayName("备注")]
public string Description { get; set; }
}
}
}
.codearea { color: black; background-color: white; line-height: 18px; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,”BitStream Vera Sans Mono”,courier,monospace,serif; }.codearea pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap pre { white-space: pre-wrap; word-wrap: break-word; }.codearea pre.alt { background-color: rgb(247, 247, 255) ! important; }.codearea .lnum { color: rgb(79, 129, 189); line-height: 18px; }只需注意:模型类型必须定义为partial,与模型关联的元数据定义包含到分离的模型类中,是模型类的一个内嵌类。最后通过MetadataType特性来指定元数据类型。