阅读目录:

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>方法,同样该泛型方法已经被类型推断过了,看泛型方法的定义:

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

上述代码中加粗的部分正是关键所在,这里扩展的其实是我们在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的呈现细节;

  1. public class Address
  2. {
  3. [UIHint("CustomAddress")]
  4. [Display(Name = "地址")]
  5. public string AddressId { get; set; }
  6.  
  7. }

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

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

视图的类型:

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

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

编辑、显示:

  1. static readonly Dictionary<string, Func<HtmlHelper, string>> defaultDisplayActions =
  2. new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) {
  3. { "EmailAddress", DefaultDisplayTemplates.EmailAddressTemplate },
  4. { "HiddenInput", DefaultDisplayTemplates.HiddenInputTemplate },
  5. { "Html", DefaultDisplayTemplates.HtmlTemplate },
  6. { "Text", DefaultDisplayTemplates.StringTemplate },
  7. { "Url", DefaultDisplayTemplates.UrlTemplate },
  8. { "Collection", DefaultDisplayTemplates.CollectionTemplate },
  9. { typeof(bool).Name, DefaultDisplayTemplates.BooleanTemplate },
  10. { typeof(decimal).Name, DefaultDisplayTemplates.DecimalTemplate },
  11. { typeof(string).Name, DefaultDisplayTemplates.StringTemplate },
  12. { typeof(object).Name, DefaultDisplayTemplates.ObjectTemplate },
  13. };
  14.  
  15. static readonly Dictionary<string, Func<HtmlHelper, string>> defaultEditorActions =
  16. new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) {
  17. { "HiddenInput", DefaultEditorTemplates.HiddenInputTemplate },
  18. { "MultilineText", DefaultEditorTemplates.MultilineTextTemplate },
  19. { "Password", DefaultEditorTemplates.PasswordTemplate },
  20. { "Text", DefaultEditorTemplates.StringTemplate },
  21. { "Collection", DefaultEditorTemplates.CollectionTemplate },
  22. { typeof(bool).Name, DefaultEditorTemplates.BooleanTemplate },
  23. { typeof(decimal).Name, DefaultEditorTemplates.DecimalTemplate },
  24. { typeof(string).Name, DefaultEditorTemplates.StringTemplate },
  25. { typeof(object).Name, DefaultEditorTemplates.ObjectTemplate },
  26. };

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

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

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

  1. @model string
  2.  
  3. <div>
  4. <h2>@Model</h2>
  5. <h2>地址:上海市、长宁区</h2>
  6. <h2>气温:-110</h2>
  7. <h2>交通:方便出行</h2>
  8. </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. CSS的margin塌陷(collapse)

    <!DOCTYPEHTML PUBLIC"-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head&g ...

  2. 1Z0-053 争议题目解析154

    1Z0-053 争议题目解析154 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 154.A database is running in ARCHIVELOG mode and ...

  3. 1Z0-053 争议题目解析512

    1Z0-053 争议题目解析512 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 512.Which two statements correctly describe the r ...

  4. FreeMarker模板开发指南知识点梳理

    freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...

  5. C#基于两种需求向图片添加水印

    使用场景 1.也就是大家经常用的,一般是图片的4个角落,基于横纵坐标来添加. 2.在图片内基于固定位置,文字始终居中.刚开始我基于第一种场景来根据水印汉字的长度来计算坐标,后来发现方法始终不可靠.现在 ...

  6. 【JUC】JDK1.8源码分析之LinkedBlockingQueue(四)

    一.前言 分析完了ArrayBlockingQueue后,接着分析LinkedBlockingQueue,与ArrayBlockingQueue不相同,LinkedBlockingQueue底层采用的 ...

  7. Moon.Orm版本维护及下载(跟踪报道)

    提示:最下面有最新的下载地址  历史记录: ).-- :: 支持Mysql,Sqlserver(点击下载) ).2013年9月14日,代码重构,加入oracle.复合主键功能(点击下载) )--,为d ...

  8. 五小步让VS Code支持AngularJS智能提示

    本文想通过配置VS Code来实现对AngularJS的智能提示.在一般的情况下对于在HTML页面是支持提示的.但是在js页面就不是很友好,它是记忆你之前的输入,要是之后有重复的输入,VS Code会 ...

  9. 基于STM32Cube的ADC模数采样设计

    1.背景         此实验建立在STM32F429核心板基础上,对于深刻了解STM32Cube使用具有深刻意义.利用DMA进行ADC采样,具有速度快,极大减少CPU消耗的优势,对于数据采集系统具 ...

  10. 【WCF】WCF中的InstanceContext与ConcurrencyMode【转】

    一.前言 最近忙于公司的在线升级项目,一个人要负责公司四大产品的在线升级,这四个产品是在Revit中以插件形式存在的,目前基于WCF来实现.等客户总量突破5万了,再重新用socket实现. 由于有服务 ...