原文:
返璞归真 asp.net mvc (4) - View/ViewEngine
作者: 介绍 asp.net mvc 之 View 和 ViewEngine - ViewData 和 TempData 都可以向 View 传递数据,其中 TempData 是保存在 Session 中的,一次请求后此 Session 会被清除
- HtmlHelper - 在 View 中显示 HTML 元素的一个帮助类
- IViewEngine - 自定义的视图引擎需要实现此接口
- VirtualPathProviderViewEngine - 实现了 IViewEngine 接口的抽象类,实现了根据指定的路径格式搜索对应的页面文件的功能(内用缓存机制)
- IView - 只有一个需要实现的方法,就是呈现 HTML 结果
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Mvc.Ajax; using MVC.Models; namespace MVC.Controllers { public class ViewDemoController : Controller { ProductSystem ps = new ProductSystem(); public ActionResult Details(int id) { var product = ps.GetProduct(id); if (product == null) { return View("NotFound"); } else { product.CategoriesReference.Load(); // 编辑 Product 的时候需要在一个 DropDownList 中选择其所对应的 Category, 所以这里要构造一个 SelectList 类型的 ViewData if (product.Categories == null) ViewData["CategoryList"] = new SelectList(new CategeorySystem().GetCategory(), "CategoryId", "CategoryName"); else ViewData["CategoryList"] = new SelectList(new CategeorySystem().GetCategory(), "CategoryId", "CategoryName", product.Categories.CategoryID); // ViewData 和 TempData 都可以向 View 传递数据,其中 TempData 是保存在 Session 中的,一次请求后此 Session 会被清除 // 在 View 中使用的时候,ViewData[key] 或 TempData[key] 即可 TempData["Temp"] = "TempData"; return View("Details", product); } } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Update(int id, FormCollection formValues) { var product = ps.GetProduct(id); // 可以通过 UpdateModel, 让系统自动为属性赋值(通过反射的方式,取得对象的属性名称,然后和 Request 的 key 做匹配,匹配成功的则赋值) UpdateModel<Products>(product); // 通过以下的方式让 UpdateModel 只更新指定属性 // string[] allowedProperties = new[] { "ProductName", "UnitPrice" }; // UpdateModel(product, allowedProperties); var category = new CategeorySystem().GetCategory(int.Parse(Request.Form["Category"])); product.CategoriesReference.EntityKey = ps.CreateEntityKey("Categories", category); if (!product.IsValid) { foreach (var validation in product.GetValidation()) { // 设置验证信息 ModelState.AddModelError(validation.PropertyName, validation.ErrorMessage); } } else { ps.Save(); } ViewData["CategoryList"] = new SelectList(new CategeorySystem().GetCategory(), "CategoryId", "CategoryName", category.CategoryID); return View("Details", product); } }}
Details.aspx <% @ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC.Models.Products>" %> < asp:Content ID ="Content1" ContentPlaceHolderID ="TitleContent" runat ="server" > Details </ asp:Content > < asp:Content ID ="Content2" ContentPlaceHolderID ="MainContent" runat ="server" > < style type ="text/css" > .bold { }{ font-weight: bold; } </ style > < h2 > Details </ h2 > <% = Html.ValidationSummary( " 输入信息有误 " ) %> <% Html.BeginForm("Update", "ViewDemo", new { id = Model.ProductID }, FormMethod.Post); %> < p > < strong > ProductID: </ strong > <% = Html.Encode(Model.ProductID) %> </ p > < p > < label for ="ProductName" > ProductName: </ label > <% = Html.TextBox( " ProductName " , Model.ProductName, new { style = " color: blue; " , @class = " bold " }) %> <% = Html.ValidationMessage( " ProductName " , " * " ) %> </ p > < p > < label for ="Category" > Category: </ label > <% -- Html.ListBox() 和 Html.DropDownList() 需要 IEnumerable<SelectListItem> 类型的数据做数据源 -- %> <% = Html.DropDownList( " Category " , ViewData[ " CategoryList " ] as SelectList) %> </ p > < p > < strong > UnitPrice: </ strong > <% = Html.Encode( string .Format( " {0:F2} " , Model.UnitPrice)) %> </ p > < p > < input type ="submit" value ="Save" /> </ p > < p > <% = TempData[ " Temp " ] %> </ p > <% Html.EndForm(); %> < p > <% = Html.RouteLink( " 返回首页 " , new { Controller = " Home " }) %> </ p > <% -- 需要使用 Web Form 方式的话,则在后置代码中继承 System.Web.Mvc.ViewPage 或 System.Web.Mvc.ViewPage<T> 即可-- %> <% -- HtmlHelper 简要说明:可以用如下的方式生成 formusing (Html.BeginForm()) { }using (Html.BeginRouteForm()) { }Html.BeginForm(); Html.EndForm();可以使用 Html.ListBox(), Html.RadioButton() 之类的来生成 html 元素Html.ValidationMessage() - 指定的 ModelName 输入信息不合法时所输出的验证信息Html.ValidationSummary() - 汇总所有验证信息验证信息可以在 Action 中用 ModelState.AddModelError() 的方式来添加验证信息的样式通过样式表修改 .field-validation-error{} .input-validation-error {} .validation-summary-errors {}Html.Encode(); Html.AttributeEncode(); 用于对输出的内容做编码Html.RenderPartial() - 引入一个 Partial ViewHtml.ActionLink() - 根据 Action 找目标Html.RouteLink() - 根据路由找目标Html.ViewContext - View 的上下文信息。包括 Controller, TempData, ViewData, 路由信息, HttpContext 等信息-- %> </ asp:Content >
2、创建一个自定义的 ViewEngine 的 Demo MyView.cs using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.IO; using System.Text.RegularExpressions; namespace MVC { /**//// <summary> /// 自定义的视图 /// 视图需要继承 IView 接口 /// </summary> public class MyView : IView { // 视图文件的物理路径 private string _viewPhysicalPath; public MyView(string viewPhysicalPath) { _viewPhysicalPath = viewPhysicalPath; } /**//// <summary> /// 实现 IView 接口的 Render() 方法 /// </summary> public void Render(ViewContext viewContext, TextWriter writer) { // 获取视图文件的原始内容 string rawContents = File.ReadAllText(_viewPhysicalPath); // 根据自定义的规则解析原始内容 string parsedContents = Parse(rawContents, viewContext.ViewData); // 呈现出解析后的内容 writer.Write(parsedContents); } public string Parse(string contents, ViewDataDictionary viewData) { // 对 {##} 之间的内容作解析 return Regex.Replace ( contents, @"\{#(.+)#\}", // 委托类型 public delegate string MatchEvaluator(Match match) p => GetMatch(p, viewData) ); } protected virtual string GetMatch(Match m, ViewDataDictionary viewData) { if (m.Success) { // 获取匹配后的结果,即 ViewData 中的 key 值,并根据这个 key 值返回 ViewData 中对应的 value string key = m.Result("$1"); if (viewData.ContainsKey(key)) { return viewData[key].ToString(); } } return string.Empty; } }}
MyViewEngine.cs using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVC { // MvcContrib 中提供了很多 ViewEngine, 还提供了以 asp.net mvc 框架为基础的一些额外的功能 // 地址:http://www.codeplex.com/MVCContrib /**//// <summary> /// 自定义的视图引擎 /// 视图引擎需要继承 IViewEngine 接口 /// VirtualPathProviderViewEngine 继承了 IViewEngine 接口,实现了根据指定的路径格式搜索对应的页面文件的功能(内用缓存机制) /// </summary> public class MyViewEngine : VirtualPathProviderViewEngine { public MyViewEngine() { // 自定义 View 路径格式 base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.my", "~/Views/Shared/{0}.my" }; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return this.CreateView(controllerContext, partialPath, string.Empty); } /**//// <summary> /// 根据指定路径返回一个实现了 IView 接口的对象 /// </summary> protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { var physicalPath = controllerContext.HttpContext.Server.MapPath(viewPath); return new MyView(physicalPath); } }}
Global.asax.cs protected void Application_Start() { // 增加新的视图引擎 ViewEngine ViewEngines.Engines.Add(new MyViewEngine()); }
CustomViewEngineController.cs using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Mvc.Ajax; namespace MVC.Controllers { /**//// <summary> /// 用于演示自定义的 ViewEngine 的 Controller /// </summary> public class CustomViewEngineController : Controller { public ActionResult Index() { ViewData["name"] = "webabcd"; ViewData["age"] = "70"; // 如果视图文件中有 {##} 形式的字符串,则 MyViewEngine 会对其做相应的解析 // 如 {#name#} 会被解析为 webabcd return View(); } }}
Index.my(智能感知在“工具 - 选项 - 文本编辑器 - 文件扩展名”中编辑) < html > < head > < title > 创建自定义的 ViewEngine 的 Demo </ title > </ head > < body > < div > name: {#name#} </ div > < div > age: {#age#} </ div > </ body > </ html >
运行结果: name: webabcd age: 70 OK posted on 2014-03-09 17:42 阅读( ...) 评论( ...)