[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面

原文:[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面

随着最终用户对用户体验需求的不断提高,实际上我们很多情况下已经在按照桌面应用的标准来设计Web应用,甚至很多Web页面本身就体现为一个单一的页面。对于这种复杂的页面,我们在设计的时候不可以真的将所有涉及的元素通通至于某个单独的View中,将复杂页面相对独立的内容“分而治之”才是设计之道。我们可以借鉴Smart Clent应用的设计方式:将一个Windows Form作为应用的容器(Smart Client Shell),在操作过程中动态地激活相应的用户控件(Smart Part)并加载到容器中。对于一个复杂页面来说,我们也只需要将其设计成一个容器,至于运行过程中动态显示的内容则可以通过Ajax调用获取相应的HTML来填充。[源代码从这里下载]

目录
一、实例演示
二、作为容器的View
三、显示联系人列表
四、弹出“修改联系人”对话框
五、联系人信息的最终修改

一、实例演示

我们先来演示一个简单的例子,假设我们要设计一个“联系人”管理的页面。该页面初始状态如左图所示,它仅仅具有一个用于输入查询条件(First Name和Last Name)进行联系人查询的表单。当用户输入相应的查询条件之后点击“Retrieve”按钮,相应的联系人列表显示以表格的形式显示出来(中图)。当我们点击作为ID的链接后,会以“模态对话框”的形式显示当前联系人的编辑“窗口”(右图)。

这个“单页面应用”是通过ASP.NET MVC开发的,接下来我们来逐步介绍如果将同一页面中的这三块不同的内容提取出来进行“分而治之”。

二、作为容器的View

如下所示的是表示联系人的Contact类型的定义,没有什么特别之处:

   1: public class Contact
   2: {
   3:     [Required]
   4:     public string Id { get; set; }
   5:     [Required]
   6:     public string FirstName { get; set; }
   7:     [Required]
   8:     public string LastName { get; set; }
   9:     [Required]
  10:     [DataType(DataType.EmailAddress)]
  11:     public string EmailAddress { get; set; }
  12:     [Required]
  13:     [DataType(DataType.PhoneNumber)]
  14:     public string PhoneNo { get; set; }
  15: }

联系人管理对应的HomeController定义如下。简单起见,我们通过一个静态字段来表示维护的联系人列表。我们仅仅列出了默认的Action方法Index,它会直接将作为“容器页面”的View呈现出来。

   1: public class HomeController : Controller
   2: {
   3:     private static List<Contact> contacts = new List<Contact>
   4:     {
   5:         new Contact{Id = "001", FirstName = "San", LastName = "Zhang", EmailAddress = "zhangsan@gmail.com", PhoneNo="123"},
   6:         new Contact{Id = "002", FirstName = "Si", LastName = "Li", EmailAddress = "zhangsan@gmail.com", PhoneNo="456"}
   7:     };
   8:  
   9:     public ActionResult Index()
  10:     {
  11:         return View();
  12:     }    
  13:      //其他Action方法
  14: }

如下所示的是Index.cshtml的定义,在这里使用了Twitter的Bootstrap,所示我们引用了相应的CSS和JS。这个主体部分包含三个<div>,分别对应着上述的三个部分。

   1: <html>
   2:     <head>
   3:         <title>Contacts</title>
   4:         <link href="@Url.Content("~/Assets/css/bootstrap.css")" rel="stylesheet" type="text/css" />
   5:         <link href="@Url.Content("~/Assets/css/bootstrap-responsive.css")" rel="stylesheet" type="text/css" />
   6:     </head>
   7:     <body>
   8:         <div class="form-search">
   9:            @Html.Partial("QueryFormPartial")
  10:          </div>
  11:         <div id="contactList"></div>
  12:         <div class="modal fade" id="contactDialog"></div>
  13:  
  14:         <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery-1.7.1.min.js")"></script>
  15:         <script type="text/javascript" src="@Url.Content("~/Assets/js/bootstrap.min.js")"></script>
  16:         <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.unobtrusive-ajax.min.js")"></script>
  17:         <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.validate.min.js")"></script>
  18:         <script type="text/javascript" src="@Url.Content("~/Assets/js/jquery.validate.unobtrusive.min.js")"></script>
  19:     </body>
  20: </html>

表示“查询表单”的部分定义在如下所示的Partial View(QueryFormPartial.cshtml),直接通过调用HtmlHelper的Partial方法呈现在当前View中。

   1: @{
   2:     Layout = null; 
   3: }
   4: using (Ajax.BeginForm("Find", new AjaxOptions { OnSuccess = "renderCustomerList" }))
   5: { 
   6:    <fieldset>
   7:        <legend>Maintain Contacts</legend>
   8:        <label class="control-label" for="firstName">First Name. :</label>
   9:        <input type="text" name="firstName" class="input-medium search-query" />
  10:        <label class="control-label" for="lastName">Last Name :</label>
  11:        <input type="text" name="lastName" class="input-medium search-query" />
  12:        <input type="submit" value="Retrieve" class="btn btn-primary" />
  13:    </fieldset>
  14: }

三、显示联系人列表

QueryFormPartial.cshtml定义了一个以Ajax方式提交的表单,目标Action为具有如下定义的Find,它根据指定的First Name和Last Name筛选匹配的联系人列表,并将其呈现在一个名为ContactListPartial的View中。

   1: public class HomeController : Controller
   2: {
   3:     //其他成员
   4:     public ActionResult Find(string firstName = "", string lastName = "")
   5:     { 
   6:         var result = from contact in contacts
   7:                         where (string.IsNullOrEmpty(firstName) || contact.FirstName.ToLower().Contains(firstName.ToLower()))
   8:                             &&(string.IsNullOrEmpty(lastName) || contact.LastName.ToLower().Contains(lastName.ToLower()))
   9:                         orderby contact.Id
  10:                         select contact;
  11:         return View("ContactListPartial",result.ToArray());
  12:     }
  13: }

如下所示的ContactListPartial.cshtml的定义,这是一个Model类型为IEnumerable<Contact>的强类型View,它以表格的形式将联系人列表呈现出来。

   1: @model IEnumerable<Contact>
   2: @{
   3:     Layout = null;    
   4: }
   5: <table class="table table-striped table-bordered">
   6:     <thead>    
   7:         <tr>
   8:             <th>ID</th>
   9:             <th>First Name</th>
  10:             <th>Last Name</th>
  11:             <th>Email Address</th>
  12:             <th>Phone No.</th>
  13:         </tr>        
  14:     </thead>
  15:     <tbody>
  16:         @foreach (var contact in Model)
  17:         { 
  18:             <tr>
  19:                 <td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td>
  20:                 <td>@contact.FirstName</td>
  21:                 <td>@contact.LastName</td>
  22:                 <td>@contact.EmailAddress</td>
  23:                 <td>@contact.PhoneNo</td>               
  24:             </tr>
  25:         }
  26:     </tbody>
  27: </table>

从QueryFormPartial.cshtml的定义可以看到,表单成功提交之后会调用一个名为renderCustomerList的JavaScript函数(@using (Ajax.BeginForm("Find", new AjaxOptions { OnSuccess = "renderCustomerList" }))),它以如下的方式定义在Index.cshtml中。从定义了看出,它将获取的数据(实际上ContactListPartial这个View最终的HTML)作为contactList这个<div>的HTML。

   1: <html>
   2:     <head>
   3:         <script type="text/javascript">
   1:  
   2:             function renderCustomerList(data) {
   3:                 $("#contactList").html(data);
   4:             }
   5:         

</script>

   4:     </head>
   5: </html>

四、弹出“修改联系人”对话框

从ContactListPartial.cshtml的定义可以看到联系人ID以一个链接的方式呈现出来,点击该链接会以Ajax的方式访问Action方法Update,当前联系人ID会作为请求的参数(<td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td>)。如下所示的是Action方法Update的定义,它根据指定的ID获取对应的联系人,并将其呈现在一个名为ContactPartial 的View中。

   1: public class HomeController : Controller
   2: {
   3:      //其他成员
   4:     [HttpGet]
   5:     public ActionResult Update(string contactId)
   6:     {
   7:         Contact contact = contacts.First(c => c.Id == contactId);
   8:         return View("ContactPartial", contact);
   9:     }
  10: }

如下所示的ContactPartial.cshtml的定义,这是一个Model类型为Contact的强类型View,它将联系人信息呈现在一个表单中。

   1: @model Contact
   2: @{
   3:     Layout = null;
   4: }
   5: @using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" }))
   6: {
   7:     <div class="modal-header">     
   8:     <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
   9:     <h3>Contact Information</h3>
  10:     </div>
  11:     <div class="modal-body">
  12:         <div class="control-group">
  13:             @Html.HiddenFor(model=>model.Id)
  14:             @Html.LabelFor(model=>model.FirstName,new{@class="control-label"})
  15:             <div class="controls">
  16:                 @Html.EditorFor(model => model.FirstName)
  17:                 @Html.ValidationMessageFor(model => model.FirstName)
  18:             </div>
  19:         </div>
  20:         <div class="control-group">
  21:             @Html.LabelFor(model=>model.LastName,new{@class="control-label"})
  22:             <div class="controls">
  23:                 @Html.EditorFor(model => model.LastName)
  24:                 @Html.ValidationMessageFor(model => model.LastName)
  25:             </div>
  26:         </div>
  27:         <div class="control-group">
  28:             @Html.LabelFor(model => model.EmailAddress, new { @class = "control-label" })
  29:             <div class="controls">
  30:                 @Html.EditorFor(model => model.EmailAddress)                
  31:                 @Html.ValidationMessageFor(model => model.EmailAddress)
  32:             </div>
  33:         </div>
  34:         <div class="control-group">
  35:             @Html.LabelFor(model => model.PhoneNo, new { @class = "control-label" })
  36:             <div class="controls">
  37:                 @Html.EditorFor(model => model.PhoneNo)                
  38:                 @Html.ValidationMessageFor(model => model.PhoneNo)
  39:             </div>
  40:         </div>
  41:     </div>
  42:     <div class="modal-footer">
  43:     <a href="#" class="btn" data-dismiss="modal">Close</a>
  44:     <input type="submit" class="btn btn-primary" value="Save" />
  45:     </div>
  46: }

联系人编译窗口的弹出最终通过调用JavaScript函数showDialog实现(<td>@Ajax.ActionLink(contact.Id, "Update", new { contactId = contact.Id }, new AjaxOptions { OnSuccess = "showDialog" , HttpMethod="GET"})</td>),具体定义如下所示。它将获取到的数据(实际上是ContactPartial这个View最终的HTML)作为第三个<div>的HTML,并按照Bootstrap的方式以模态对话框的形式将其呈现出来。至于中间的两行代码,在于解决动态添加表单无法实施验证的问题。

   1: <html>
   2:     <head>
   3:         <script type="text/javascript">
   1:            
   2:             function showDialog(data) {
   3:                 $("#contactDialog").html(data);
   4:                 $("#contactDialog form")
   5:                     .removeData("validator")
   6:                     .removeData("unobtrusiveValidation");
   7:                 $.validator.unobtrusive.parse($("#contactDialog form"));
   8:                 $("#contactDialog").modal();
   9:             }            
  10:         

</script>

   4:     </head>
   5: </html>

五、联系人信息的最终修改

通过ContactPartial.cshtml的定义可以看出编辑联系人表单最终以POST的方式提交到HomeController的Action方法Update(@using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" }))),该Action方法具有如下的定义。它在完成修改之后,返回字符串“OK”表明联系人修改成功。

   1: public class HomeController : Controller
   2: {
   3:     //其他成员
   4:     [HttpPost]
   5:     public string  Update(Contact contact)
   6:     {
   7:         contacts.Remove(contacts.First(c=>c.Id == contact.Id));
   8:         contacts.Add(contact);
   9:         return "OK";
  10:     }
  11: }

联系人修改表单提交后关闭当前窗口并加载新的数据通过具有如下定义JavaScript函数Reload实现(@using(Ajax.BeginForm("Update", null, new AjaxOptions { HttpMethod = "Post", OnSuccess = "reLoad" }, new { @class = "form-horizontal" }))),该函数依然定义在Index.cshtml中。

   1: <html>
   2:     <head>
   3:         <script type="text/javascript">
   1:  
   2:             function reLoad(data) {
   3:                 if (data == "OK") {
   4:                     $("#contactDialog").modal("hide");
   5:                     $(".form-search form").submit();
   6:                 }
   7:             }
   8:         

</script>

   4:     </head>
   5: </html>
时间: 2024-09-17 04:56:36

[ASP.NET MVC] 利用动态注入HTML的方式来设计复杂页面的相关文章

asp.net MVC利用自定义ModelBinder过滤关键字的方法(附demo源码下载)_实用技巧

本文实例讲述了MVC利用自定义ModelBinder过滤关键字的方法.分享给大家供大家参考,具体如下: 前面一篇主要讲解了如何利用ActionFilter过滤关键字,这篇主要讲解如何利用自己打造的ModelBinder来过滤关键字. 首先,我们还是利用上一篇<asp.net MVC利用ActionFilterAttribute过滤关键字的方法>中的实体类,但是我们需要加上DataType特性,以便于我们构造的ModelBinder通过DataTypeName识别出来: using System

[ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证

很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者是一个经过认证的用户.质询-应答(Chanllenge-Response)"是用户认证采用的一种常用的形式,认证方向被认证方发出质询以要求其提供用于实施认证的用户凭证,而被认证方提供相应的凭证以作为对质询的应答.旨在目标Action方法执行之前实施身分认证的AuthenticationFilter也

Asp.net MVC利用自定义RouteHandler来防止图片盗链

你曾经注意过在你服务器请求日志中多了很多对图片资源的请求吗?这可能是有人在他们的网站中盗 链了你的图片所致,这会占用你的服务器带宽.下面这种方法可以告诉你如何在ASP.NET MVC中实现一个 自定义RouteHandler来防止其他人盗链你的图片. 首先,我们来回顾一下当一个请求发往ASP.net MVC站点时的情景,IIS收到请求并将请求转到 ASP.net,然后根据URL,或者更确切来说:被请求文件的扩展名.在IIS7 integrated模式下(默认模式), 所有的请求都会匹配到ASP.

ASP.NET MVC的四种验证编程方式_实用技巧

我们可以采用4种不同的编程模式来进行针对绑定参数的验证. 一.手工验证绑定的参数 在定义具体Action方法的时候,对已经成功绑定的参数实施手工验证无疑是一种最为直接的编程方式,接下来我们通过一个简单的实例来演示如何将参数验证逻辑实现在对应的Action方法中,并在没有通过验证的情况下将错误信息响应给客户端.我们在一个ASP.NET MVC应用中定义了如下一个Person类作为被验证的数据类型,它的Name.Gender和Age三个属性分别表示一个人的姓名.性别和年龄. public class

利用视觉艺术为网站增彩 巧妙设计—让页面活起来

随着互联网的发展,Web页面在我们的生活中已经是无处不在,如何利用视觉艺术为你的Web产品增彩,也成了产品设计者逐步完善的一门课程. 一个完整的Web页面是需要点线面的合理结合,每一个页面都是一个神奇的空间,同时他的深度,广度和作者赋予的元素美感决定了这个页面的可观赏性. 好的创作依附与好的灵感.灵感是一个很微妙的东西,它是指不用平常的感觉器官而能使精神互相交通,亦称远隔知觉.或指无意识中突然兴起的神妙能力.或指作家因情绪或景物所引起的创作情状. 如果你在创作的时候没有灵感,不防停下苦思冥想,一

ASP.NET MVC 权限管理(二) 实体模型设计

上一篇文章写了关于项目的基本开发组织和项目用到的一些东西,这篇文章就开始设计实体模型了,好了,废话不多说. 一.实体模型基类 因为每个模型实体都需要有一个编号,状态这些基本的东西,为了遵守MVC的"不要重复自己"的原则,共有的东西就写到一个公共类去,以前开发我都是用自增的Int作为主键,这一次呢就打算试用一下GUID作为数据库的主键编号,要是有不懂的地方,大家赶紧指出来啊~~ 有码有真相: /// <summary> /// 模型基类 /// </summary>

《ASP.NET MVC 4 实战》---- 1.3 ASP.NET MVC 3/4的新特性

1.3 ASP.NET MVC 3/4的新特性 ASP.NET MVC 4 实战 除了对.NET 4有新的依赖性之外,MVC 3.4版有许多改进和一些新的特性.这些新特性包括: 本节中将简要介绍每一种新特性,然后整个这本书都将对它们做更为深入的探讨.我们还将介绍移动模板.Web API,并在第23章和第24章介绍MVC 4特有的其他特性. 1.3.1 Razor视图引擎 新的ASP.NET Web Pages技术的核心组件之一是Razor视图引擎.该引擎提供了一种在同一个文件中将代码与标记混合在

ASP.NET MVC Music Store教程(3):视图和视图模型

转自http://firechun.blog.163.com/blog/static/31804522201102711480936/ 到目前为止,我们仅仅从控制器动作返回字符串,这是一个了解控制器如何工作的好方法,但这并不是你想要的真实的Web应用程序.我们想要一个更好的方法为访问我们站点的浏览器产生HTML,使用模板文件可以更容易地定制发回的HTML内容. 添加视图模板 要使用视图模板,可以修改HomeController的Index方法,让它返回ActionResult,就象下面这样返回V

如何在 ASP.NET MVC 中集成 AngularJS(1)

介绍 当涉及到计算机软件的开发时,我想运用所有的最新技术.例如,前端使用最新的 JavaScript 技术,服务器端使用最新的基于 REST 的 Web API 服务.另外,还有最新的数据库技术.最新的设计模式和技术. 当选择最新的软件技术时,有几个因素在起作用,其中包括如何将这些技术整合起来.过去两年中,我最喜欢的一项技术就是设计单页面应用(SPA)的 AngularJS.作为一个微软stack开发者,我也是使用 ASP.NET MVC 平台实现 MVC 设计模式和并进行研究的粉丝,包括它的捆