无刷新转页面? 这是我前些天提出一个想法。为什么会有这样的想法呢?主要是考虑到目前如果使用Atlas作开发的话,那就不可以避免的要下载它的脚步库。一般情况下,我们都会下载的是Atlas.js(少数情况才会下载AtlasRuntime.js),这个文件就要238KB,如果是Debug版本的程序的话,那么将会下载Debug版本的Atlas.js,而这个文件就要360KB。(所以要发布asp.net程序时,设置web.config的debug="false"很重要的.)再得寸进尺点,原来每次转页面时,都需要重新下载所以有CSS,JS,Image,更新ViewState等等,这些都需要花费非常多的资源和时间(可以通过Fiddler查看一下访问一次页面的过程)。那么,是不是有一种办法,做到既可以改变页面的功能,又可以不重新刷新页面呢?这样效率那该提高多少啊?
不用框架页面,那就尝试使用动态加载用户控件的方式吧。主要思路是这样的,把原来做在页面上功能封装到一个用户控件去,利用导航菜单来动态加载不同的用户控件。由于大部分情况下,页面的框架基本都是一样的,不同的功能页面也就是部份内容的不同,和执行不同的功能而已。这就是给这样的思路提供了一个前提环境条件,做一个页面(功能类似一个MasterPage),在这个页面上做好页面总体布局,在需要动态改变的位置上放一个PlaceHolder,用Atlas UpdatePannel包起来,设置合适的更新条件刷新这块区域的内容。
简单来看一下实现步骤。新建一个Web Site工程,创建三个不同功能的WebUserControl,在Default.aspx页面上放一个Menu控件做导航,利用它的MenuItemClick事件作导航,而不要直接设置NavigateUrl属性。
接下来就如何动态加载UserControl的问题了,动态加载UserControl需要注意的一些细节在这篇文章里(Asp.Net中页面运行时动态载入的UserControl内元素的事件处理的注意事项)已经一个很好的讨论了。我的做法重写CreateChildControls方法,然后在这个方法里动态加载用户控件。但是还需要解决一个问题,如何才能知道要加载哪个用户控件呢?因为根据页面的事件模型,控件的处理事件是在页面加载,处理完后才被处理的,也就Menu1_MenuItemClick事件是晚于CreateChildControls方法被执行的。那在CreateChildControls方法怎么才知道要加载的控件的呢?那么如果能在这个方法中得到引发页面回发的事件源和参数就可以解决了。经过调试和查看Page类的源代码,发现有在Page类中有这两个常量定义,postEventArgumentID (值为:"__EVENTARGUMENT")和postEventSourceID(值为: "__EVENTTARGET")。既然有这两个常量定义,肯定也可以得到它们的请求值,最终找到了可以在Request.Form取到他们的值,而且也是我希望的值。来看看页面代码:
不是很复杂的代码,应该能一看就明白了。这里就不再浪费篇幅了。
总结:通过这种方法来改变页面功能的好处是,可以大大减少加载页面的时间,减小服务器的压力。但是可能还有很多我没有考虑到的问题会出现。希望能有一个讨论的结果。另外,在加载用户控件的部分前面,由于前面没有看到那两个常量,使用了另一种方法,但是当从一个UserControl转到另一个UserControl时,新的UserControl的第一次回发事件将不会被执行,这个问题一直没能解决。在附下载的例子中的default.aspx就还存在这样的问题,找到问题的起因,但是一直没能明白过来。