精通ASP.NET MVC ——视图

文章非常长,仅仅用于记录自己学习。 

创建自定义视图引擎

创建自定义视图引擎的价值是,演示请求处理管道如何工作,并完善关于MVC架构如何操作的知识,视图引擎实现IViewEngine接口,如下图所示:

    public interface IViewEngine{ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache);ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache);void ReleaseView(ControllerContext controllerContext, IView view);}

视图引擎的作用是将对视图的请求转化成ViewEngineResult对象。 这个接口中两个方法是FindView  FindPartialView,给它们传递的是描述请求的参数:处理该请求的控制器(ControllerContext对象)、视图名及其布局,以及是否允许视图引擎重用其缓存结果。当框架对ViewResult进行处理时,会调用这个两个方法。最后一个方法是ReleaseView(释放视图),当视图不在需要时被调用(从其名称不难看出,该方法的作用是释放视图所占用的资源)。

当请求一个视图时,ViewEngineResult类使视图引擎能够对MVC框架做出响应。代码如下图所示:

using System.Collections.Generic;namespace System.Web.Mvc
{public class ViewEngineResult{public IEnumerable<string> SearchedLoactions{get;private set;}public IView View {get;private set;}public IViewEngine ViewEngine{get;private set;}public ViewEngineResutlt(IEnumerable<string> searchedLoactions){if(searchedLoactions == null){throw new ArgumentNullException("searchedLocations");}SearchedLoactions = searchedLoactions}public ViewEngineResutlt(IView view,IViewEngine viewEngine){if(view == null){throw new ArgumentNullException("view");}if(viewEngine == null){throw new ArgumentNullException("viewEngine");}View = view;ViewEngine = viewEngine;}}
}

可以通过两个构造器中的其中一个来表示一个结果,如果视图引擎能够对请求提供视图,那么可以用以下构造器创建一个ViewEngineResult: 

public ViewEngineResutlt(IView view,IViewEngine viewEngine)

如果视图引擎不能对请求提供视图,那么可以使用如下构造器: 这一版本是查找视图位置的一个枚举。如果找不到视图,就会将枚举的信息显示给用户。

public ViewEngineResutlt(IEnumerable<string> searchedLoactions)

视图引擎的最后一个构造块是IView接口,如下图所示: 

public interface IView{void Render(ViewContext viewContext, TextWriter writer);}

把一个IView实现传递给ViewEngineResult对象的构造器,然后它会被视图引擎方法所返回。MVC框架会调用Render方法(把IView实现传递给ViewEngineResult对象构造器时,自然便会调用IView接口中的这个Render方法)。 到目前为止,ViewContext对象定义了一些属性,这些属性给你提供请求信息以及MVC框架如何处理它的细节。

有用的ViewContext属性
名称描述
Controller返回处理当前请求的IController实现
RequestContext返回当前请求的细节
RouteData为当前请求返回的路有数据
TempData返回和请求相关的临时数据
View返回将要处理请求的IView接口的实现。很明显,如果你正在创建一个自定义视图实现,它将是当前类。
ViewBag返回一个表示视图的object
ViewData返回一个包含模式视图包和元数据的视图模型数据字典。

这些属性中最有趣的是ViewData,它返回一个ViewDataDictionary对象。定义了一些有用的属性,如下图所示:

有用的ViewDataDictionary
名称描述
keys为字典中的数据返回键值集合,他们可用来访问视图包属性
Model为请求返回视图模型对象
ModelMetadata返回一个可以用来反映模型类型的ModelMetadata对象
ModelState返回有关模型的状态信息

根据以上知识,创建一个自定义视图引擎, 首先新建一个空白项目,创建一个Home控制器,如下图所示:

    public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Messge = "Hello,World";ViewBag.Time = DateTime.Now.ToShortTimeString();return View("DebugData");}public ActionResult List(){return View();}}

创建一个自定义IView,在项目中新建一个Infrastructure的文件夹,创建一个DebugDataView.cs的新的类文件,如下图所示: 

namespace WebApplication1.Infrastructure
{public class DebugDataView : IView{public void Render(ViewContext viewContext, TextWriter writer){Write(writer, "---Routing Data---");foreach (string key in viewContext.RouteData.Values.Keys){Write(writer, "key:{0},value:{1}", key, viewContext.RouteData.Values[key]);}Write(writer, "---View Data---");foreach (string key in viewContext.ViewData.Keys){Write(writer,"key:{0},value:{1}",key,viewContext.ViewData[key]);}}private void Write(TextWriter writer, string template, params object[] values){writer.Write(string.Format(template,values) + "<p>");}}
}

 

视图引擎的目的是产生一个ViewEngineResult对象,它或者包含一个IView,或者是一个用于搜索适当视图的位置列表。现在已经有了IView的实现,于是可以创建视图引擎,在Infrastructure的文件夹下新建一个DebugDataViewEngine.cs的类文件,代码如下图所示:

namespace WebApplication1.Infrastructure
{public class DebugDataViewEngine : IViewEngine{public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache){return new ViewEngineResult(new string[] { "No View (Debug Data View Engine)" });}public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache){if (viewName == "DebugData"){return new ViewEngineResult(new DebugDataView(), this);}else{return new ViewEngineResult(new string[] { "No view (Debug Data View Engine)" });}}public void ReleaseView(ControllerContext controllerContext, IView view){}}
}

注册自定义视图引擎 

视图引擎需要在 Global.asax 的 Application_Start 方法中进行注册,代码如下图所示:

ViewEngines.Engines.Add(new DebugDataViewEngine());

静态的ViewEngine.Engines集合含有一组在应用程序中安装的视图引擎。MVC框架支持在一个单一的应用程序中安装多个引擎。当处理一个ViewResult时,动作调用器获取这组已经安装的视图引擎,并依次调用它们的FindView方法。

一旦动作调用接收到一个含有IView方法的ViewEngineResult对象。便会停止调用FindView方法。如果有两个或者多个引擎能够对同视图的请求进行服务,这意味着在ViewEngines.Engines集合中添加引擎的顺序是很重要的,代码如下图所示:

ViewEngines.Engines.Insert(0,new DebugDataViewEngine());

测试视图引擎 

运行程序,效果如下图所示:

           

如果导航到/Home/List,该动作方法调用View方法请求其默认视图,这是一个我们不支持的视图,就会报错,如下图所示: 

            

从上述报错来看,Razor和ASPX视图也在列表中,可以清除其他类型的视图引擎, 代码如下:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new DebugDataViewEngine());

理解Razor视图渲染

Razor视图引擎会编译应用程序中的视图,以改善性能。视图会被转化成C#类,然后被编译。这是在视图中能够如此方便地包含C#代码片段的原因。

程序启动前,视图不会被编译。只有程序启动后才能触发视图编译过程。出于方便,会将视图文件生成的类写成磁盘上的C#代码,然后进行编译,这意味着能够看到一个视图的C#语句。这些语句可以在C盘的某些隐蔽的目录下被找到,并且文件名和它们所包含的类名不对应。


配置视图搜索位置

在查找视图时,Razor视图引擎遵循MVC框架早期版本建立起来的约定。例如,如果请求与Home控制器先关的Index视图时,Razor会审查一下视图列表:

/Views/Home/Index.cshtml

/Views/Home/Index.vbhtml

/Views/Shared/Index.cshtml

/Views/Shared/Index.vbhtml

Razor实际上不会在磁盘上查找这些视图文件,因为它们还没有被编译成C#文件。Razor查找的是表示这些视图的编译类。.cshtml文件是含有C#语句的模板,而.vbhtml文件含有Visual Basic语句。

Razor视图引擎搜索属性
属性描述默认值

ViewLoactionFormats

MasterLocationFormatsPartiaView

LocationFormats

查找视图、分部视图、以及布局的位置

~/ Views / {1} / {0}.cshtml,

~/ Views/ {1} / {0}.vbhtml,

~/ Views/ Shared / {0}.cshtml,

~/ Views/ Shared/ {0}.vbhtml,

AreaViewLocationFormats

AreaMasterLocationFormats

AreaPartialViewLocationForms

为一个区域查找视图、分部视图,以及布局位置

~/ Areas / {2} / Views / {1} / {0}.cshtml,

~/ Areas / {2} / Views / {1} / {0}.vbhtml,

~/ Areas / {2} / Views / Shared / {0}.cshtml,

~/ Areas / {2} / Views / Shared / {0}.vbhtml

这些属性是在Razor之前引入的,这是每组三个属性具有相同值的原因。每个属性都是一个字符串数组,它们是用合成字符串格式化符号来表示的。以下是与占位符对应的参数值:

{0} 表示视图名。

{1} 表示控制器名。

{2} 表示区域名。

通过创建一个RazorViewEngine子类,可以改变Razor搜索的视图文件。 在Infrastructrue文件夹中,创建了一个名称为CustomerLocationViewEngine的视图引擎,代码如下图所示:

    public class CustomLocationViewEngine:RazorViewEngine{public CustomLocationViewEngine(){ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml","~/Views/Common/{0}.cshtml"};}}

以上代码对 ViewLoactionFormats设置了一个新值。新数组只包含用于.cshtml文件的条目。此外,已经将查找共享视图的位置修改为了View/Common,而不是Views/Shared。并且在Global.asax的Application_Start方法中,注册此引擎:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomLocationViewEngine());

最后创建/View/Common文件夹,并添加一个名称为List.cshtml的视图文件。 代码如下图所示:

@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>List</title>
</head>
<body><div> <h3>This is the /Views/Common/List.cshtml View</h3></div>
</body>
</html>

启动程序,并导航到/Home/List时,执行效果如下图所示:

             

 


 使用分段

Razor引擎支持分段的概念,Razor分段能够灵活的控制将视图的哪一个部分插入到布局之中,以及把他们插入到哪里。

下面对/Views/Home/Index.cshtml文件进行编辑,如下图所示:


@model string[]
@{Layout = "~/Views/Shared/_Layout.cshtml";
}@section Header{<div class="view">@foreach (string str in new[] {"Home","List","Edit" }){@Html.ActionLink(str,str,null,new { style = "margin:5px"})}</div>
}<div class="view">This is a lists of fruit names@foreach (string name in Model){<span><b>@name</b></span>}
</div>@section Footer
{<div class="view">This is the footer</div>
}

在上图代码中,创建了名称为“Header” 和 “Footer”的分段。分段的内容可以混用HTML标记和Razor标签。你可以在布局中使用@RenderSection 辅助器方法来指定分段要插入的位置。修改Views/Shared/_Layout.cshtml文件,代码如下图所示:

<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><style type="text/css">div.layout {background-color:lightgray;}div.view {border:thin solid black;margin:10px 0;}</style><title>@ViewBag.Title</title>
</head>
<body>@RenderSection("Header")<div class="layout">This is part of the layout</div>@RenderBody()<div class="layout">This is part of Layout</div>@RenderSection("Footer")<div class="layout">This is part of Layout</div>
</body>
</html>

在Razor对布局进行解析时,RenderSection辅助器方法会显示视图中指定名称的分段内容。视图中未包含在分段中的内容会插入布局中使用RenderBody辅助器方法。 运行程序,结果如下图所示:

                     

注意:一个视图只能定义在布局中被引用的分段。如果视图在视图布局中午没有对应的@RendSection辅助器调用分段,MVC框架会报错。 

一般情况下,不要分段与视图的其余的部分混杂在一起。其约定是,在视图的开始或者结尾部分定义分段,以便更容易看到哪些内容区域被处理成分段,对于那些需要RenderBody辅助器捕捉的内容,可以把这些定义成一个独立的分段,如下图所示:

@model string[]
@{Layout = "~/Views/Shared/_Layout.cshtml";
}@section Header{<div class="view">@foreach (string str in new[] {"Home","List","Edit" }){@Html.ActionLink(str,str,null,new { style = "margin:5px"})}</div>
}@section Body
{<div class="view">This is a lists of fruit names@foreach (string name in Model){<span><b>@name</b></span>}</div>
}@section Footer
{<div class="view">This is the footer</div>
}

以上这种办法有利于建立更清晰的视图,并减少了RenderBody捕捉无关内容的情况。为了使用这种方法,我们得用Rend而Section("Body")替换对RenderBody辅助器的调用。 代码如下图所示:

<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><style type="text/css">div.layout {background-color:lightgray;}div.view {border:thin solid black;margin:10px 0;}</style><title>@ViewBag.Title</title>
</head>
<body>@RenderSection("Header")<div class="layout">This is part of the layout</div>@RenderSection("Body")<div class="layout">This is part of Layout</div>@RenderSection("Footer")<div class="layout">This is part of Layout</div>
</body>
</html>

对分段进行测试

检查一个视图是否已经定义了布局中的一个特定的分段,可以使用如下代码,修改了_layout.cshtml:

@if (IsSectionDefined("Footer"))
{@RenderSection("Footer")
}
else
{<h4> This is the deafault footer </ht>
}

渲染可选分段 

默认情况下,视图中必须含有布局中的RendSection的所有分段。如果缺少分段,MVC框架将会报错,修改_layout.cshtml代码并运行,结果如下图所示:

 

定义可选分段,只需加上一个false值即可:如果视图定义了它,其内容将被插入到结果中,否则也不会抛出异常,代码如下图所示:

 @RenderSection("scripts",false)

 


使用分部视图

通常需要在应用程序中多个不同的地方,使用同样的Razor标签 和 HTML 标记片段。采取的办法不是重复这些标记,而是采用分部视图(Partial View).

新建一个名称为MyPartial.cshtml分部视图,代码如下图所示:

<div>This is the massage from the partial view.@Html.ActionLink("This is a link to the Index action", "Index");
</div>

修改List.cshtml页面,代码如下图所示: 


@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>List</title>
</head>
<body><div> <h3>This is the /Views/Common/List.cshtml View</h3></div>
</body>
</html>
@Html.Partial("MyPartial")

提示:Razor视图引擎对分部视图的查找方式,于规则视图相同 (即在~/Views/<controller> 和 ~/Views/Shared文件夹中进行查找)。这意味着,可以创建控制器专用的的特殊版本的分部视图,它会覆盖Shared文件夹下进行查找。

运行程序,效果如下: 

           


使用强类型分部视图 

可以创建强类型分部视图,然后在渲染这个分部视图时,传递要使用的视图模型对象。

新建一个名为MyStrongTypedPartial.cshtml的分部视图,代码如下图所示:

@model IEnumerable<string><div>This is message from the partial view.<ul>@foreach (string str in Model){<li>@str</li>}</ul>
</div>

并修改/View/Common/List.cshtml文件,代码如下所示: 


@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>List</title>
</head>
<body><div> <h3>This is the /Views/Common/List.cshtml View</h3></div>
</body>
</html>
@Html.Partial("MyStronglyTypedPartial",new[] {"Apple","Orange","Pear" })

运行效果如下图所示:

             

 


使用子动作 

子动作是通过视同调用的动作方法。当你希望将某种控制器逻辑用于应用程序的多个地方时,子动作可以让你避免重复的控制器逻辑。子动作和动作之间的关系,如同分部视图和视图的关系一样。无论何时,当希望显示某些数据驱动的“小部件”,这些“小部件”要出现在多个页面上,而且含有与主动作无关的数据时,你可能就会希望使用子动作。

创建一子动作,代码如下图所示:

        [ChildActionOnly]public ActionResult Time(){return PartialView(DateTime.Now);}

新增Time.cshtml页面,代码如下图所示: 

@model DateTime<p> The time is @Model.ToShortDateString()</p>

启动程序,再次导航到/Home/List,效果如下图所示:

           

通过提供一个匿名类型对象,其属性对应于子动作方法的参数名,可以将参数传递给动作方法,代码如下图所示:

        [ChildActionOnly]public ActionResult Time(DateTime time){return PartialView(DateTime.Now);}
@Html.Action("Time",new { time = DateTime.Now})

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548531.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用列表选择框控件

本例使用列表选择框控件,并向其中添加删除列表项&#xff0c;程序运行如下图所示。 程序代码如下。 using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace eg38_checklistBoxApp {public partial class Form1 : Form…

精通ASP.NET MVC ——辅助器方法

辅助器方法(Helper Method)&#xff0c;其作用是对代码块和标记进行打包&#xff0c;以便能够在整个MVC框架应用程序中重用。 首先新建一个项目&#xff0c;添加一个Home控制器&#xff0c;如下图所示&#xff1a; public class HomeController : Controller{// GET: Homepubli…

精通ASP.NET MVC ——模型绑定

模型绑定&#xff08;Model Binding&#xff09;是指&#xff0c;用浏览器以Http请求方式发送的数据来创建.Net对象的过程。 准备示例项目 新建一个空的MVC项目&#xff0c;名叫MvcModels&#xff0c;接下去会以此项目来演示各种功能。 在Models文件夹中创建一个Person.cs类…

精通ASP.NET MVC ——模型验证

文章内容较长&#xff0c;用于记录自己学习。模型验证&#xff08;Model Vaildation&#xff09;是确保应用程序所接受的数据适合于绑定到模型&#xff0c;并且在不合适时给用户提供有用的信息&#xff0c;以帮助他们修正问题的过程。 准备示例项目 新建一个空的MVC项目&…

[wbia 2.2] 对检索结果进行评估

评估对检索系统的性能&#xff1a; 由于我们这里的检索结果&#xff0c;是主要根据PageRank的排名&#xff0c;以及Lucene对文本的分词和相关性计算的最后得分&#xff0c;进行权值调整后得到的排名结果。 这里对我们检索系统的进行性能评估&#xff0c;这里主要评估的是检索结…

错误175:具有固定名称MySql.Data.MySqlClient的ADO.NET提供程序未在计算机或者应用程序配置文件中注册或者无法加载

背景&#xff1a; EF连接MySQL时报错&#xff0c;截图如下图所示&#xff1a; 网上翻阅了很多资料&#xff0c;感觉有一篇文章说的比较靠谱&#xff1a;点击阅读。解决问题的大致过程如下&#xff1a; 在尝试使用MySQL&#xff0c;ADO.NET&#xff08;数据库优先&#xff09;和…

精通ASP.NET MVC ——URL和Ajax辅助器方法

Ajax(或者&#xff0c;如果你愿意&#xff0c;也可以称为AJAX)是 Asynchronous JavaScripts and XML(异步JavaScripts与XML)。其XML部分并不如它往常那样意义重大&#xff0c;但是异步部分却使AJax十分有用。这是后台请求服务器数据&#xff0c;而不必重载Web页面的一种模型。M…

精通ASP.NET MVC ——控制器可扩展性

MVC中引导动作方法执行过程的请求流程管道中&#xff0c;有两个重要的部件&#xff1a;控制器工厂(Controller Factory) 和 动作调用器&#xff08;Action Invoker&#xff09;。控制器工厂负责创建对请求进行服务的控制器实例&#xff0c;动作调用器负责查找并调用控制器类中的…

永中向香港博览会主办方演示云办公(转载)

4月16号“香港国际资讯博览会”主办方香港贸发局对永中云办公产品非常感兴趣&#xff0c;由永中员工演示&#xff0c;并拍摄了演示视频。转载于:https://blog.51cto.com/premium/837675

Backbone.js学习笔记

为什么80%的码农都做不了架构师&#xff1f;>>> http://documentcloud.github.com/backbone var todoItem new TodoItem(); todoItem.url /todo; todoItem.fetch(); todoItem.get(description)var TodoItem Backbone.Model.extend({urlRoot: /todos }); var tod…

ASP.NET MVC中使用Autofac实现简单依赖注入

本文参考资料&#xff1a; 1、https://www.cnblogs.com/RayWang/p/11128554.html。 2、https://www.cnblogs.com/eedc/p/6127181.html 3、https://www.cnblogs.com/ancupofcoffee/p/5007649.html#top 前言 关于IoC和DI(依赖注入)的概念网上一搜一大把。简单来说&#xff0c;Io…

初探EntityFramework——来自数据库的EF设计器

本文通过简单的示例&#xff0c;先初步了解下EF四种设计模式之一&#xff1a;来自数据库的EF设计器。 来自数据库的EF设计器&#xff0c;顾名思义&#xff0c;需要有新建的数据库和表结构&#xff0c;才能生成EF设计器&#xff0c; 在本地新建数据库KTStore&#xff0c;并且新建…

初探EntityFramework——空EF设计器模型

如果没有任何现存数据库架构&#xff0c;可以使用空的EF设计器模型。本文将通过简单示例&#xff0c;了解如何使用空EF设计器模型。 新建空的控制器应用程序EFDesignerDemo&#xff0c;如下图所示&#xff1a; 在项目中右键&#xff0c;选择“添加”&#xff0c;然后是“新建项…

初探EntityFramework——来自数据库的Code First

Entity Framkwork从第二版&#xff08;EF4&#xff09;开始&#xff0c;支持新的CodeFirst模式&#xff08;程序代码优先&#xff09;&#xff0c;以自定义类定义数据模型。简化了EF的开发过程。本文章使用简单的示例来说明如何使用来自数据库的CodeFirst模式。 新建一个空的控…

初探EntityFramework——空Code First模型

如果不是从现有的系统升级&#xff0c;想要创建全新的项目可以从“空Code First模型开始”。“空CodeFirst模型”要先创建类&#xff0c;Visual Studio会从项目第一次执行的时候根据连接自动创建需要的数据库结构。本文将简单示例说明如何使用“空CodeFirst模型”。 新建控制台…

初探EntityFramework——实体类结构映射

实体类与数据表的映射有一套专用的规则。Code First 采用的惯例优于预先设置的设计&#xff0c;在没有任何设置的情况下&#xff0c;自动检测模型结构并推导出默认设置以简化类的设计&#xff0c;因此不需要特别设置类的属性即可完成模型设计。 例如&#xff0c;当DbContext的模…

深入了解EntityFramework——数据注解属性

当惯例规则不符合设计需求时&#xff0c;我们可以使用数据注解配置打造更合适的数据库模型。本文根据示例项目对常用的数据注解属性做一个简要的举例说明。 EFCodeFirst使用的约定大于配置的的编程模式&#xff0c; 这种模式利用默认约定根据我们的领域模型建立概念模型。然我们…

Android上实现柱状图表

Android上实现柱状图算法实现 第一步&#xff1a; 获取Android设备的屏幕大小 第二步&#xff1a; 在View对象中使用Canvas绘制蓝色边框与白色背景XY轴两条线&#xff0c;代码如下 第三步&#xff1a; 绘制柱状图标题 第四步&#xff1a; 根据数据集计算出每个系列数据所占X轴的…

深入了解EntityFramework——Fluent API

Fluent API 除了惯例原则与属性数据注解外&#xff0c;FluentAPI是另一种支持实体类配置设置的方式。与属性数据注解相比&#xff0c;它提供了更广泛的功能与设置弹性。实体类若同时设置了数据注解&#xff0c;则采用的优先权是“Fluent API” > "数据注解" &g…

深入了解EntityFramework——Lazy Loading与Eager Loading

Lazy Loading&#xff1a;延迟加载。Eager Loading&#xff1a;贪婪加载。 首先通过一个简单的控制台应用程序例子说明延迟加载&#xff1a; 订单主表和订单从表&#xff0c;并且订单主表和订单从表是一对多的关系&#xff0c;代码如下图所示&#xff1a; //订单主表public cl…