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