(本帖在版工的台湾旧 Blog 中,发表日期为 2007/12/19,于 2008/09/29 改写过)
传统的 AJAX 网页,浏览器的「历程 (history)」不会去做记录,因此当使用者按下浏览器的「上一页 (back;previous)」按钮后,无法回到前一份动态更新的页面;且浏览器「书签;我的最爱 (bookmark)」所记录的,也不是动态更新后的页面。微软在 2007 年 7 月、2007 年 12 月,分别推出了「ASP.NET Futures」、「ASP.NET 3.5 Extensions Preview」套件,提出了这项问题的解决方案,前者使用一种新增的 History 控件,将浏览器的「巡览 (navigate)」历程信息,经过「序列化 (serialization)」并加密后,附加在 URL 网址后方,以供浏览器作为辨识之用;后者直接将此 History 控件及其功能,整并至新一代 ASP.NET 3.5 的 ScriptManager 控件当中。因此在新一代的 ASP.NET 3.5 和 AJAX,已不再有此 History 控件,而改由 ScriptManager 控件去做处理 [1]。
* 版工注:日前开放下载的 VS 2008 SP1 (亦即 ASP.NET 3.5 SP1) 的 ScriptManager 控件才有此功能,该版的 ScriptManager class 也才有相关的属性、方法和事件。VS 2008 还没有加入。
本帖提供一个版工我撰写的 ASP.NET 2.0 示例,让置于 AJAX UpdatePanel 中的 GridView 控件,在使用者单击 GridView 的页码换页后,或移至别页再移回本页后,都能保留 GridView 原本的页数和状态;且此时再按浏览器的「上一页、下一页」,都会自动产生作用,自行对应至 GridView 的页码。本示例经过 IE 6 SP1、IE 7、Firefox 2.0.0.11、 Firefox 3.0.3 测试后,都能正常执行。
本帖的 ASP.NET 2.0 示例代码下载点:
https://files.cnblogs.com/WizardWu/080929.zip
(执行本示例,需要 SQL Server 的 Northwind 数据库)
以 VS 2005 或 IIS 开启下载示例后,执行 testHistory1.aspx,会自动连结您本机的 SQL Server 2000/2005 的 Northwind 数据库,得到如下图 1 的画面。这个示例和传统的 AJAX + GridView 网页,有三大不同点:
1、当 GridView 换页时,IE (或 Firefox) 左上方的「上一页、下一页」按钮会自动启用;若为传统的 AJAX 网页则不会。
2、假设您换页到 GridView 的第二页,当您按 ProductName 字段里的文字 hyperlink 进到别的页面,再按浏览器左上方的「上一页」回来时,GridView 仍会停在第二页;若为传统的 AJAX 网页则不然,而是一律跳回 GridView 的第一页。
3、当 GridView 换页后,此时若将该页加入浏览器的「书签 (bookmark)」,会一并记录是在 GridView 的哪一页;若为传统的 AJAX 网页则不会记录。
图 1 当 GridView 换页时,注意浏览器左上方的「上一页、下一页」会自动启用;若为传统的 AJAX 网页则不然
一般我们将 GridView 放进 UpdatePanel 里,当您按下 GridView 右下方的页码换页后,浏览器无法回上一页 (呈现灰色只读);而且当您移至别页,再按浏览器的「上一页」回到有 GridView 的这一页后,GridView 的页数也会自动跳回第一页,而非我们预期的、原本离开时的那个页数 (例如上图 1 中的第 2 页)。
而本帖下载范例,引用 ASP.NET Futures 套件中的 History 控件,利用存储在 URL 后面的 navigating 信息,同时解决上述多个问题。
请参考上图 1,当您执行本帖下载示例的 testHistory1.aspx,并按下 GridView 的页码换页后,会发现网址后面,自动加了一长串加密过的「巡览历程;导航历程」数据,这是用 History 控件的 AddHistoryPoint method 所达成的。请参考下载示例中的 GridView1_PageIndexChanged 事件处理函数。
其原理为,History 控件的 AddHistoryPoint 方法,会将 state (如本帖中 UpdatePanel 里 GridView 的目前所在页数) 指派给一个 Dictionary<TKey, TValue> 型别变量 (state) 的 Key,并将这份 history-point 信息做过序列化和加密后,以乱码的型式附加在浏览器 URL 后面 (参考上图 1);当使用者换页时 (不论是按下 GridView 的页码,或是按下 GridView 里的文字 hyperlink 进到 testHistory2.aspx 时),都会再加入新的 history-point 信息。
此后当您按下浏览器左上方的「上一页」按钮,即会触发 History 控件的 Navigate 事件。此时开发人员就可以自己撰码控制,如何将已经附加至 URL 的数据重新建置 page state (例如本帖中,要回到 GridView 的第几页)。请参考下载示例中的 History1_Navigate 事件处理函数。
此一 History 控件,及本帖下载示例的 Bin 活页夹里的 Microsoft.Web.Preview.dll,版工取自于微软在 2007 年年中推出的「ASP.NET Futures」套件,下载来源为 ASP.NET 的原文官方网站,下载网址如下 (2008/09/29 时仍可下载,只是套件的版本比本帖用的更新):
http://www.asp.net/downloads/
http://www.asp.net/downloads/futures/
图 2 「ASP.NET Futures」套件的下载网页
此「ASP.NET Futures」套件,可安装在 VS 2005、VS 2008、VWD 2005、VWD 2008 中。安装套件后,当您开启 Visual Studio 并新增一个网站时,会多出两个叫做「ASP.NET Futures AJAX Web Site」、「ASP.NET Futures Web Site」的选项;而在 Visual Studio 的「工具箱」中,会多出两组 Index Tab (选项卡) 和十几个新控件,如下图 3 所示。但这些控件和微软的其它套件,或今年刚推出的 VS 2008 SP1 的功能和控件,是否会有版本冲突,版工我未测试过,不得而知。
图 3 安装好套件后,VS 工具箱会多出两组 Index Tab (选项卡) 和许多控件
结论:
要启用 history navigation 的控件,除了 GridView 以外,当然您也可以改成 DetailsView、FormView。虽然 History 控件在 ASP.NET 3.x 之后已不存在,已被整并至 ScriptManager 控件中,但根据 Dino Esposito 所述 [1],其观念和使用方式仍很类似。
本帖的示例,虽然是用 VS 2005 / ASP.NET 2.0 撰写,但同样的写法及 History 控件,在 VS 2008 / ASP.NET 3.5 仍可继续延用。若您想把既有的 ASP.NET 2.0 AJAX 网站,用 History 控件改写其 navigation 功能,将来即使网站要迁移至 ASP.NET 3.x 平台,也不会有版本兼容性问题,只要把 Microsoft.Web.Preview.dll、Web.config 设定值,一并拷贝至 ASP.NET 3.x 的网站及 Bin 活页夹里,即可延用既有的代码和语法。但如果您已升级至 VS 2008 SP 1 / .NET 3.5 SP 1,其 ScriptManager 控件 (类) 即已内建此功能,即无须再依靠这个 History 控件了。
---------------------------------------------------------------------------------
参考文件:
[1] Dino Esposito 于 2007/12/17 在其 blog 中,提到微软在 2007 年 12 月初最新发布的「ASP.NET 3.5 Extensions Preview」套件,已经将 History 控件整合进新一代的 ScriptManager 里面,且使用方式仍大同小异。新的 ScriptManager 类,仍然有 Navigate 事件和 AddHistoryPoint 方法 (这点版工我已用 VS 2008 SP1 试过):
http://dotnetslackers.com/articles/aspnet/AFirstLookAtASPNETExtensions35HistoryPoints.aspx
[2] ASP.NET Futures (July 2007): Managing Browser History and Back Button Support in ASP.NET AJAX:
http://quickstarts.asp.net/Futures/ajax/doc/history.aspx
http://quickstarts.asp.net/Futures/default.aspx
[3] Using ASP.NET 3.5 History Control with ASP.NET 2.0 (2008/08/03)
http://www.dotnetglobe.com/2008/08/using-asp.html
[4] ASP.NET AJAX History Part 1: Server-Side (2008/02/06):
http://lostintangent.com/2008/02/06/aspnet-ajax-history-part-1-server-side/
[5] A First Look at ASP.NET Extensions 3.5—History Points:
http://dotnetslackers.com/articles/aspnet/AFirstLookAtASPNETExtensions35HistoryPoints.aspx
[6] What's in the Futures Release?
http://www.asp.net/downloads/futures/
[7] VS 2008 Multi-Targeting Support:
http://weblogs.asp.net/scottgu/archive/2007/06/20/vs-2008-multi-targeting-support.aspx
[8] ASP.NET 3.5 Extensions CTP Preview Released:
http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-3-5-extensions-ctp-preview-released.aspx
[9] Microsoft ASP.NET Futures (July 2007) 中 History 在客户端的使用:
http://www.cnblogs.com/chsword/archive/2007/09/19/897929.html
[10] ASP.NET AJAX IN ACTION 中译本第 13 章:
http://www.manning.com/gallo
---------------------------------------------------------------------------------
相关文件:
[11] ASP.NET 3.5 Extensions: All About Dynamic Data:
http://blogs.msdn.com/brada/archive/2007/12/13/asp-net-3-5-extensions-all-about-dynamic-data.aspx
[12] ASP.NET 3.5 extensions-DotNet开发圣殿:
http://blog.sina.com.tw/dotnet/article.php?pbgid=4907&entryid=575383