阅读目录:

7.HtmlHelper、HtmlHelper<T>中的ViewModel的类型推断

8.控制ViewModel中的某个属性的呈现(使用PartialView部分视图细粒度控制ViewModel的呈现)

9.模板的装饰者模式(PartialView与ViewModel的嵌套使用(简))

7.HtmlHelper、HtmlHelper<T>中的ViewModel的类型推断

在View中用来根据当前View中引入的强类型ViewModel生成HTMLDom结构的核心功能都被封装在以HtmlHelper为首的对象模型中,包括HtmlHelper<T>泛型类型,它直接派生自HtmlHelper基类,这两个类型的功能都是围绕着如何生成前端所需要的HTML结构和一些常用的UI元素;

但是这两个类型所能做的事情很有限,它们只是庞大生成功能的核心模型;我们使用的都是围绕着这两个类型的扩展方法,如:

@Html.EditorForModel()

在当前View中引用的Html属性其实是一个HtmlHelper<T>类型的属性,定义代码:

public HtmlHelper<TModel> Html { get; set; }

该类型被定义在public abstract class WebViewPage<TModel> : WebViewPage类中,其实该类是一个模板化代码生成的基类;我们在ASP.NETMVC项目中添加的所有View文件都会直接或间接的继承自该类型,在View中引入的类型定义:

@model  MvcApplication4.Models.Customer

正是这里泛型类型的类型参数,所以围绕着HtmlHelper<T>的扩展方法才变成灵活的泛型的代码生成接口;因为他们彼此通过强大的泛型类型推断,依次的推断下去,最终会到达扩展方法的内部,如:

@Html.EditorFor(model => model.Shopping)

这意思是说在View中输出一个编辑model.Shopping属性的文本框HtmlDom结构,但是我们调用的明明是一个没有任何类型形参的方法,其实它已经通过上面说将的环节进行了类型关联;

画红线的部分是View所使用的强类型HtmlHelper<T>对象,类型参数是我们在View中通过@model的方式定义的;画绿色的部分也是强类型的EditorFor<T>方法,同样该泛型方法已经被类型推断过了,看泛型方法的定义:

public static class EditorExtensions
{
  public static MvcHtmlString EditorFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression);
}

上述代码中加粗的部分正是关键所在,这里扩展的其实是我们在View中引入的强类型参数的HtmlHelper<MvcApplication4.Models.Customer>,这样任何围绕HtmlHelper<T>进行扩展的扩展方法都会最终使用到类型ViewModel;

8.控制ViewModel中的某个属性的呈现(使用PartialView部分视图细粒度控制ViewModel呈现)

对于ViewModel的呈现一直都是被系统控制着,虽然一个简单的字符串类型字段可以用一个文本框的HtmlDom结构方式呈现出来,但是那仅仅是代表着没有任何业务概念的功能性设置,也就是出发点是从CLR类型系统考虑的,而不是特定领域角度;如果这个字符串代表着某种业务概念,那么我们希望通过更人性化的方式让用户使用,而不是一个硬生生的文本框;我们可能会需要提供了一个供自动输入提示的HtmlDom结构,该结构可能还需要其他的UI成员协助,如:自动提示可能需要JS、后台Service接口等一系列成员相互协调完成;

这是一个简单的需求,在大型项目中这样的功能很常见,也是到处会使用到,不单单是一个两个页面,N多页面都会有一点点的差异性,但是整体功能都会差不多,这样我们只需要在设计的时候适当的提供一些接口就可以了;

那么ASP.NETMVC是如何生成前台所需要的HtmlDom结构的呢? 前面一章我们总结了,对于ViewModel的呈现形式只会有两种,一种是Edit一种是Display,不会有其他的呈现形式,所以在围绕着HtmlHelper对象的扩展方法中大多数都是以这种类别区分的,Edit一组,Display一组;

到目前位置我们已经知道ViewModel与View之间的桥梁是Model元数据,可以简单的理解为HtmlHelper<T> 一系列扩展方法都是通过获取Model元数据信息来控制到底需要输出什么形式的HtmlDom结构,而Model元数据都是通过Model元数据控制特性来完成的,这就可以通过控制Model元数据来控制Model的呈现细节;

public class Address
{
[UIHint("CustomAddress")]
[Display(Name = "地址")]
public string AddressId { get; set; } }

我们在Address类型中为AddressId属性加上一个UIHint类型的特性,其实意思是想说明我们在程序内部使用的是使用地址ID,而在现实的时候我们希望将原来很单调的地址ID编程一个更人性化的地址显示方式,比如:位于什么省、什么市等等一些其他的地理信息;

在ASP.NETMVC内部有一个internal static class TemplateHelpers 类型的模板辅助类,该类是大部分模板化输出的帮助接口,在该类的内部定义了一套模板化使用的字典:

视图的类型:

static readonly Dictionary<DataBoundControlMode, string> modeViewPaths =
new Dictionary<DataBoundControlMode, string> {
{ DataBoundControlMode.ReadOnly, "DisplayTemplates" },
{ DataBoundControlMode.Edit, "EditorTemplates" }
};

这里定义了两组类型,也就是显示、编辑,这两组类型将作为查找自定义模板的物理文件夹路径,同样ModelMedata中的同一个属性在不同的显示类型中将有不同的判断作用;

编辑、显示:

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 },
}; 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 },
{ typeof(bool).Name, DefaultEditorTemplates.BooleanTemplate },
{ typeof(decimal).Name, DefaultEditorTemplates.DecimalTemplate },
{ typeof(string).Name, DefaultEditorTemplates.StringTemplate },
{ typeof(object).Name, DefaultEditorTemplates.ObjectTemplate },
};

这是两组显示模式的模板化操作方法的字典,可以看出同一个HiddenInput特性将在不同的显示模式先输出不同的HtmlDom结构;

在我们的ASP.NETMVC项目中要同样的有两组文件夹DisplayTemplates、EditorTemplates,这两个文件夹将会是系统查找的路径;

我们在DisplayTemplates目录下创建了一个用来显示客户地址信息的自定义模板,其实也就是PartialView部分视图,用来重用UI;在该部分视图中,我们写点测试数据:

@model string 

<div>
<h2>@Model</h2>
<h2>地址:上海市、长宁区</h2>
<h2>气温:-1~10</h2>
<h2>交通:方便出行</h2>
</div>

然后我们刷新一下界面,看如何个性化了地址显示;

这样我们就可以控制细粒度的ViewModel显示;

9.模板的装饰者模式(PartialView与ViewModel的嵌套使用(简))

其实我们应该能够领悟到通过PartialView与HtmlHelper彼此互相嵌套能让原本单一的部分视图变成一个强大的具有设计模式功能的模板装饰者模式;想想看,如果我们将这里的AddressId类型再设计成复杂的类型,然后在该复杂的类型内部我们嵌套了一个原本在其他地方使用的地址类型ViewModel,而且刚好该类型也具有相应的部分是视图,这样我们就可以将ViewModel的嵌套使用与PartialView嵌套使用相结合,这样就可以使用类似设计模式中的装饰者模式来完成很多UI上的展现重用功能;

作者:王清培

出处:http://www.cnblogs.com/wangiqngpei557/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

.NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(三)的更多相关文章

  1. .NET/ASP.NETMVC Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(一)

    .NET/ASP.NETMVC Model元数据.HtmlHelper.自定义模板.模板的装饰者模式(一) 阅读目录: 1.开篇介绍 2.Model与View的使用关系(数据上下文DataContex ...

  2. MVC中Model元数据及绑定机制

    ASP.NET MVC的Model为View Model,表示最终呈现在View上的数据,而Model元数据的一个重要的作用在于控制对象在View上的呈现方式.说得更加具体点,就是基于某种数据类型的M ...

  3. MVC之Model元数据

    Contronoller激活之后,ASP.NET MVC会根据当前请求上下文得到目标Action的名称,然后解析出对应的方法并执行之. 在整个Action方法的执行过程中,Model元数据的解析是一个 ...

  4. .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)

    阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...

  5. 【笔记】ASP.NET MVC Model元数据

    问题1:什么叫Model元数据? Model元数据,是针对数据类型的一种描述信息.由于复杂类型(或者说类型嵌套的存在,比如CustomerModel中有一个属性为复杂类型Address)的存在,因此M ...

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

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

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

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

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

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

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

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

随机推荐

  1. iframe编程的一些问题

    前几天做一个用iframe显示曲线图的demo,发现对iframe的contentDocument绑定 onclick事件都无效,而在页面中对iframe.contentDocument的onclic ...

  2. Cesium应用篇:3控件(2)BaseLayerPicker

    所有范例均在github中搜索:ExamplesforCesium BaseLayerPicker控件非常简单,似乎没什么可说的,确实非常的简单,但作为一个底图选择控件,可以说是最基本的一个控件. C ...

  3. 多个Activity相互调用和Intent

    MainActivity.java和OtherActivity.java的相互调用 首先MainActivity.java是Android程序自带的,新建一个类OtherActiviy extends ...

  4. 网络基础 : OSI参考模型

    Overview OSI规范的作用之一就是帮助在不同的主机之间传输数据. OSI模型包含7层,它们分为两组. 上面3层指定了终端中的应用程序如何彼此通信以及如何与用户交流: 下面4层指定了如何进行端到 ...

  5. 自定义MVC框架

    我们在学习自定义MVC框架的时候常常会听到Model1 ,Model2和MVC.那么什么是Model1 什么是Model2什么又是MVC呢? 什么是Model1? Model1就是一种纯jsp开发技术 ...

  6. 跨平台运行ASP.NET Core 1.0

    前言 首先提一下微软更名后的叫法: ASP.NET 5 更名为 ASP.NET Core 1.0 .NET Core 更名为 .NET Core 1.0 Entity Framework 7 更名为  ...

  7. WPF模板

    WPF的中模板有三种:ControlTemplate.ItemsPanelTemplate.DataTemplate,他们继承抽象类FrameworkTemplate,下面是它们的继承关系: Wind ...

  8. CSS基础之居中显示

    这些天忙完了一些项目后,终于有时间来总结一下了.自己就把做项目过程中的体会和理解到的一些东西和大家分享一下.有错请指正!! 在css中,元素居中显示,是基础也是一个小难点.我们经常不知为何总是不能把元 ...

  9. nginx 添加nginx-http-concat模块

    github地址:https://github.com/alibaba/nginx-http-concat/tree/master 简单的描述一下吧,网上说的安装新的模块需要重新编译nginx,具体的 ...

  10. 超简单的激活Microsoft Office 2016 for Mac 方法

    1.简介: 2016年9月14日更新本博客,激活工具同样适用于Office 15.25(160817)版本.我此前在国外网站上找到一个App,下载之后运行,直接点击一个黑色开锁的标识按钮,输入系统密码 ...