代码改变世界

Atlas 服务器端控件 - 易用但不灵活

2006-10-22 14:54  Cat Chen  阅读(609)  评论(0编辑  收藏  举报

首先,我会把Atlas服务器端控件区分为两类,纯服务器端控件和客户端逻辑封装控件。前者类似WebControl派生出来的控件那样,它自身并非直接呈现(render)一个客户端元素的实例就算,而是拥有复杂的服务器端逻辑,它呈现出来的HTML由交错的规则决定着;至于后者,则类似HtmlControl派生出来的控件,它所做的基本上就是将自身呈现为一个单一的客户端元素,其服务器端属性比较直接的生成客户端元素的属性或者子元素,不过客户端逻辑封装控件输出的不是HTML,而是Atlas特有的xml-script。

纯服务器端控件是Atlas服务器端的重点,这些控件在Microsoft.Web.UI而不在Microsoft.Web.UI.Controls,由此也可以看出他们的核心地位,它们是ScriptMananger(ScriptManagerProxy)和UpdatePanel。

首先说说ScriptManager,它都是一个非常有用的控件,扔一个ScriptManager到Page上面,它就会自动帮你生成引用Atlas核心js的引用,这样Atlas函数库就能够被使用,xml-script也能被解释。对于一个ScriptManager,你可以向它添加Script和Service引用。

可添加Script引用的包括Atlas内置的Script模块(AtlasUIDragDrop、AtlasUIGlitz、AtlasUIMap)和是你自己的js文件,如果添加的是js文件你可以使用"~"路径运算符以确保无论在什么路径的页面都能正确引用这个js文件。

添加Service引用的Service是ASP.NET Web Service,添加引用后你可以直接在JavaScript或xml-script中调用该Web Service而无须管后台是怎么实现的。另外,ScriptManager还有一个重要的属性,就是EnablePartialRendering,启用后ScriptManager就会去分辨一个PostBack是正常提交的PostBack还是XMLHttpRequest发回来的异步PostBack,如果是后者它就会优化处理,详细下面再解释。

然后说说UpdatePanel,这就是Atlas让你最容易开发一个“看起来很Ajax”的应用的地方。所谓的UpdatePanel,其实就是圈定一个区域,里面的控件或者外部注册为异步调用的控件触发PostBack时并不真正提交页面而是用XMLHttpRequest发送异步PostBack,之后分析从服务器端返回的HTML并更新这个区域内的HTML代码。你可以设置一个UpdatePanel不是每次都需要更新内容,当一个异步PostBack发生时就根据一堆的Trigger设置来判断一个UpdatePanel是否在本次异步PostBack时需要更新,同时ScriptManager开启了EnablePartialRendering的话则只有需要更新的区域内的HTML才会被发送到客户端,这样就可以节省沟通成本。

虽然这样看起来UpdatePanel非常灵活,区域有多大以及什么条件下才更新都能够设置,一眼看起来设置适当的话非常好用。但其实并不存在“设置适当”,UpdatePanel并不是万能,它不能像普通控件那里放在任何区域之内、包容任何控件、在页面生命周期的任何阶段声明,所以不是你喜欢怎样放就怎样放。而且当UpdatePanel多起来Trigger也不容易设置完美,总会导致应该更新而没更新的情况,而那个时候你就会想还是把所有UpdatePanel设置为总是更新算了。

UpdatePanel最坏的地方我认为是破坏对象结构。服务器端控件和客户端的DOM都是树状结构,目标就是保持逻辑的局部性,所以Response.Write和Document.Write这种破坏局部性的操作方式我觉得都不应该被使用,而UpdatePanel区域的刷新就如Response.Write一样,一刷就是整个区域。虽然在服务器端区域内的还是控件,还是可以按控件进行逻辑处理,但是在客户去这样一刷,DOM元素都被破坏掉了,区域内增加删除修改了哪些DOM元素完全没办法知道,这时候该区域内外的View和Model都独立,要建立一个跨越区域边界的Controller也不容易,当内部的View和Modal被整个替换掉的时候,Controller完全不知道变更的细节,而需要自己去适应新送上来的View和Model。对此暂时我觉得可行的解决方案就是建立一个内部的Controller,让该Contoller负责和外部Contoller的沟通,而该Controller由服务器端生成,所以它可以知道新旧的View和Model之间的变更细节。

简单来说,用UpdatePanel就如用不闪烁的IFrame一样,传统的做法能够马上用上,但效率不高,灵活性也低,最后你会发现不如整个页面都放在一个大的UpdatePanel里面,让它“看起来不闪烁”就算了。