All articles| All Pictures| All Softwares| All Video| Go home page| Write articles| Upload pictures

Reading number is top 10 articles
C#基础学习,——,异步编程篇_.net资料_编程技术
扩展GridView(四)——每行复选框的全选与取消全选_[Asp.Net教程]
.net获取w3wp进程对应的应用程序池_[Asp.Net教程]
C#网络应用编程基础练习题与答案(五)_[Asp.Net教程]
php+mysq 修改用户密码(用password加密)_[PHP教程]
server2008系统安装Microsoft.NET,Framework3.5_.net资料_编程技术
用javascript-css实现GridView行背景色交替、点击行变色_[Asp.Net教程]
基于.NET数字处理程序的框架设计_.net资料_编程技术
利用UrlRewrite,asp.net动态生成htm页面(补充说明2)_[Asp.Net教程]
js版sliderBar(滑动条)控件_JavaScript技术_编程技术
Reading number is top 10 pictures
妹子最好别玩单反
教你22句话
世界五大海盗
A man's favorite things6
初五接财神啦!五路财神齐来到
Chinese paper-cut grilles art appreciation5
Absolutely shocked. National geographic 50 animal photographys5
Sora aoi after swimming
Is said to be a Chinese female artist fame explicit pictures before2
The real super beauty1
Download software ranking
天龙八部最新服务端
Love the forty days
Unix video tutorial3
Professional killers2 for Android
徐若瑄成名作“魔鬼天使”
Eclipse 4.2.2 For Win64
Boxer Classic video2
Ashlynn Video2
c#程序设计案例教程
WebService在.NET中的实战应用教学视频 → 第2集
归海一刀 published in(发表于) 2014/1/30 1:07:02 Edit(编辑)
不妨来做个尝试:UpdatePanel,for,ASP.NET,MVC_[Asp.Net教程]

不妨来做个尝试:UpdatePanel,for,ASP.NET,MVC_[Asp.Net教程]

不妨来做个尝试:UpdatePanel for ASP.NET MVC_[Asp.Net教程]

  先来发一通牢骚。


  其实这是一篇迟发布近2个月的文章。事实上在ASP.NET MVC Preview 2发布之前我就已经将这篇文章的所有内容准备完毕了。当时想,就等Preview 2发布吧,而真一旦Preview 2发布之后却又懒得进行移植——移植了之后却又懒得写文章。这一拖就是近2个月,毫无长进。可能工作等其他事情的确多了些,但是扪心自问,也并没有忙到不可开交。时间往往都是在点点滴滴间浪费的。唉,可能是自视太高,越来越不愿意写一些普普通通的介绍性文章,导致可写的东西大大减少。不过话说回来,其实打算写的,甚至多次说过要写得东西也并不少,为什么就就是没有动笔呢?其实还是一个“懒”字——当年的勤奋劲儿到哪里去了呢?


  言归正传。先解释一下标题,什么是“UpdatePanel for ASP.NET MVC”呢?ASP.NET AJAX中的UpdatePanel相信大家都有所了解。可惜的是,ASP.NET MVC框架的诞生“毁灭”了大量基于PostBack的控件,首当其冲地可能就是UpdatePanel了。如果没有PostBack,UpdatePanel就失去了全部作用,甚至不如一些绑定控件,至少它们还能够用于展示。为UpdatePanel长吁短叹之后,我们不禁又开始怀念UpdatePanel的优势:“透明”。在UpdatePanel的帮助下,实现AJAX操作对于开发人员几乎完全透明。我们要做的仅仅是将需要AJAX更新的内容用UpdatePanel包装起来,一切都是那么优雅。


  我们能否在ASP.NET MVC中拯救UpdatePanel呢?也许是可以的吧,但这更像是一个“不可能完成的任务”。我不是传说中的阿汤哥,因此重新为ASP.NET MVC量身定制一个AJAX解决方案似乎更为可行。虽然我们不会苛求一个新生事物从诞生开始就趋向完美,但即使只是一个原型,它也必须严格遵守的一些原则:



  • 不得破坏MVC中的协议(协作,职责等等)
  • 对开发人员尽可能地透明

  Nikhil Kothari曾经提出了他在ASP.NET MVC框架下的AJAX解决方案。如果您还不了解他的做法,那么我先在这里进行一点概括。Nikhil扩展了Controller使之支持一种Ajax操作,于是我们在代码中就可以写如下代码:


public class TaskListController : AjaxController {
...
public void CompleteTask(int taskID) {
if (String.IsNullOrEmpty(Request.Form["deleteTask"]) == false) {
InvokeAction("DeleteTask");
return;
}

Task task = _taskDB.GetTask(taskID);
if (task != null) {
_taskDB.CompleteTask(task);
}

if (IsAjaxRequest) {
if (task != null) {
RenderPartial("TaskView", task);
}
}
else {
RedirectToAction("List");
}
}
...
}


  与AjaxController类似,Nikhil也为ViewPage和ViewControl提供了一些扩展方法,因此目前在View(List.aspx)中我们就能看到如下的代码:




<% foreach (Task task in Tasks) { %>


<% this.RenderPartial("TaskView", task); %>


<% } %>


  在View和Controller中都存在对于RenderPartiel方法的调用,它们的作用就是向客户端输出一个“Partial Template”生成的HTML代码。而在ASP.NET MVC的默认配置中,Partial Template即为User Control。而在TaskView这个Partial Template中可以看到一些辅助方法:



" class="taskPanel">
<% Ajax.Initialize(); %>
<% this.RenderBeginAjaxForm(
Url.Action("CompleteTask"),
new {
Update = "taskItem" + Task.ID,
UpdateType = "replace",
Completed = "endUpdateTask"}); %>




<%= Html.Encode(Task.Name) %>

<% this.RenderEndForm(); %>
<% Ajax.RenderScripts(); %>


  这些辅助方法的作用是生成一些触发AJAX更新的标签及脚本,当用户点击RenderBeginAjaxForm与RenderEndForm方法生成的tag之间的提交按钮时,网页将会向服务器端发出一个AJAX请求,而服务器端的Action并最终会通过RenderPartial方法输出一个Partial Template生成的HTML。服务器端最终输出的HTML将会被替换或添加到页面的某个元素内。这就形成了一个AJAX效果。这个解决方案从某些方面看上去很酷,尤其是生成的代码可以添加到某个元素中,而不单单是如同UpdatePanel的替换,例如Nikhil在他的例子中就使用了这个特性实现了一个添加功能。不过如果使用之前提出的原则来衡量的话,似乎这个解决方案并不十分理想。


  原因很简单,因为不够透明。


  也有评论认为,Controller中的逻辑不该根据一个请求AJAX与否而进行不同处理(Nikhil的解决方案使用RenderPartial来替代RenderView为AJAX操作进行输出),因此这个解决方案破坏了MVC的职责。我不这么认为,但是我希望能做到这一点,因为做到这一点即意味着绝对的透明。绝对透明则意味着Controller将一个应用程序是否AJAX的决定权完全交给了客户端,这点非常理想,因为AJAX完全是一个表现层的概念。ASP.NET AJAX中的UpdatePanel在这方面的表现可圈可点(虽然还远不够完美),因此我最后决定也为ASP.NET MVC开发一款类似UpdatePanel的组件。值得庆幸的是,ASP.NET MVC默认使用WebForm页面作为视图模板,在这个强大的模型之下,构建出这样一个AJAX解决方案(的原形)似乎并不十分困难。


  我将这个控件命名为MvcAjaxPanel。MvcAjaxPanel与UpdatePanel最大的区别在于后者接收的是PostBack,而前者接收的只是普通的HTTP请求。Post“Back”意味着Post过后回到了原来的Page,而ASP.NET MVC的请求往往会被引导至不同的页面。因此如何跨页面进行内容更新是MvcAjaxPanel首要解决的问题。最终我选择了为每个MvcAjaxPanel指定一个UpdateAreaID的做法。



...


  当页面向服务器端发出一个AJAX请求时将会附带页面中的UpdateAreaID信息,而服务器端的Action并不会意识到这一点,因此依旧按照寻常逻辑指定一个视图模版并输出HTML。不过,如果视图模板中的MvcAjaxPanel发现这个请求实际上是一个符合约定的AJAX请求(请注意,只有View组件意识到这是个请求的性质),则会使用新的方法来替换标准的输出。这时候模板就会根据客户端传递过来的UpdateAreaID,寻找页面上具有同样属性值的MvcAjaxPanel,有选择性地输出内容。在客户端就会有对应的JavaScript代码接收服务器端的数据,并且更新页面中的相应区域。


  很明显,MvcAjaxPanel的工作原理与UpdatePanel有颇多相似之处,也做到了一定程度上的透明。而且与Nikhil的解决方案相比,一个非常重要的优势就是可以一次更新页面中的多个区域——其实这也就是UpdatePanel的特性之一。而且这种对Controller透明的做法又有一个天然的特点,那就是能够轻松地在不支持AJAX的浏览器中使用传统的方式切换页面。


  服务器端的实现原理并不复杂,不过作为解决方案的另一个关键部分,如何在客户端触发一个AJAX提交也是一个值得思考的话题。UpdatePanel的方式可谓“全自动”:页面加载时将会把服务器端的Trigger信息输出至客户端,然后在客户端截获form的提交事件,并通过UniqueID或DOM结构等方式来判断这次提交是否该转化为AJAX方式。不过在一个ASP.NET MVC页面中几乎不会出现产生PostBack的元素,相反会有大量的普通链接,它们才是AJAX更新的主要截获目标。


  为此我提供了一些JavaScript代码,截获一个链接原本的目标地址并将其转化为一个AJAX请求。我在这里通过示例中的代码来展示这种使用方式(这个示例源于Brad Abrams提供的ASP.NET MVC示例,不过我舍弃了Northwind数据库与Entity Framework,取而代之的是XML数据以及自定义的简单Model。此外,我也将其移植到ASP.NET MVC框架的0416 Build中):


<% foreach (var category in this.ProductCategories)
{ %>


  • <%= Html.ActionLink(
    c => c.List(category, 1),
    category,
    new { onclick = "mvcAjax.get(this, event)" })%>
  • <%
    } %>


      这段代码来自分类列表页。与AJAX改进之前的代码相比,唯一的区别就是额外指定了元素的onclick事件(加粗部分)。在onclick事件执行中,这个链接默认的跳转行为将被取消,取而代之的是一个AJAX请求,请求的目标便是ProductsController中名为List的Action。


      我们可以使用上面的方式应对普通链接,那么又该如何将一个客户端from的提交行为也变成AJAX操作呢?以下依旧是示例中的代码:


    action="<%= Url.Action("Update", new { id = this.Product.ProductID }) %>"
    onsubmit="mvcAjax.submit(this, event);">






    Name:


    <%= Html.TextBox("Name", this.Product.Name) %>



    ...





      在截获了form的submit事件之后,客户端将会收集该form中的所有input、select等值,组成一个请求的body,并且以HTTP POST的方式发出一个AJAX请求。余下的事情和之前就没有什么区别了。


      与UpdatePanel相比,MvcAjaxPanel的客户端截获方式可谓“纯手工”,但是我并不认为这会造成什么问题。ASP.NET MVC强调的就是职责分离,而这种分离并不仅仅体现在代码上,也体现在开发人员的职责上。在开发ASP.NET MVC应用程序时,负责View的是前端开发工程师,对他们来说JavaScript与AJAX可谓是再熟悉不过的技术。在合时的地方手动编写一些JavaScript调用反而会让他们得到无比的自由性。例如在之前的代码示例中,调用mvcAjax.get或mvcAjax.submit方法时完全可以在前后自由地加入额外操作或者条件判断。这就不会像使用UpdatePanel时,如果需要使用JavaScript提交一个AJAX更新,还需要借助不登大雅之堂的trick


      也正因为如此,Nikhil提出的解决方案非常不错,它能够和前台开发人员的自定义逻辑进行灵活地结合。此外,通过阅读ASP.NET MVC框架0416 Build的代码,我发现在新版本的ASP.NET MVC中似乎将会内置这种AJAX解决方案了——不过这也的确符合微软的一贯做法,不是吗?:)


      这个AJAX解决方案原型的使用方式和工作原理已经描述完了,如果您对其具体实现感兴趣,或者想亲自尝试一下,可以下载文章末尾的附件。附件中的解决方案包含三个项目,MvcAjax为提供MvcAjaxPanel的项目,而MvcWebApp是一个普通的ASP.NET MVC示例程序,而MvcAjaxWebApp自然就是添加AJAX效果之后的结果了。在示例中,我还在Master Page中定义的菜单(即页面左侧的菜单)里显示了一块当前时间,这是为了体现MvcAjaxPanel的“一次提交,多处更新”的特点。


      不过需要强调的是,这仅仅是个原型。或者说这只是一种实现上尝试,在很多细节方面并没有作太多追求。如果要成为一个完善的AJAX解决方案,还需要作大量的改进。例如:



    • 提供一些客户端的hook供前台开发人员使用(如提交前、接受后、或者处理一个提交还没有返回,客户端就发起另一个请求的情况等等)。
    • 更强大的功能,更好的开发体验(如客户端触发机制)
    • 异常处理
    • 支持脚本
    • 支持跳转(Redirection)
    • ...

      此外,作为面向ASP.NET MVC特有的AJAX解决方案,也有一些额外的问题需要考虑。最典型的问题之一就是在使用ASP.NET MVC时很少使用模板控件,而更多的使用页面中的循环,那么如何让MvcAjaxPanel在循环内容生效?我也产生过一些想法,但是如果要真正确定下来最终的实现方式,很多东西还需要进一步思考。如果您对于这个AJAX解决方案有什么建议或其他任何想法,也请尽快告诉我。


      最后再说一件有趣的事情:在我实现了这个原型之后的某一天,忽然意识到这个控件似乎不光可以为ASP.NET MVC使用,也能够用于普通的WebForms应用程序。这真是一个令人意外的发现。


    附件:源代码及使用示例


    来源:http://www.cnblogs.com/JeffreyZhao







    添加到del.icio.us 添加到新浪ViVi 添加到百度搜藏 添加到POCO网摘 添加到天天网摘365Key 添加到和讯网摘 添加到天极网摘 添加到黑米书签 添加到QQ书签 添加到雅虎收藏 添加到奇客发现 diigo it 添加到饭否 添加到飞豆订阅 添加到抓虾收藏 添加到鲜果订阅 digg it 貼到funP 添加到有道阅读 Live Favorites 添加到Newsvine 打印本页 用Email发送本页 在Facebook上分享


    Disclaimer Privacy Policy About us Site Map

    If you have any requirements, please contact webmaster。(如果有什么要求,请联系站长)
    Copyright ©2011-
    uuhomepage.com, Inc. All rights reserved.