DropDownList、ListBox由于Items是保存在ViewState中,回传后服务端会从ViewState恢复所有Items,所以,客户端对options的设置在回传后无法获取、保持。
一个解决思路是通过在页面Submit的时候,在客户端解码viewstate,找出相应items集合,根据客户端对该集合的处理,进行重新设置,然后再把更改过的viewstate重新编码提交。由于一个页面的viewstate可以是非常之大,所以这个操作在客户端的压力可能会较大。
另一个思路是将客户端对options的变更保存到隐藏域中提交,然后服务端根据该隐藏域的信息重建ListControl的items。相对而言,该实现效率更高。这个解决方案就是基于该思路来做的。我继承DropDownList、ListBox,让每个控件实例与一个隐藏域一起输出到客户端,在客户端Form.onsubmit事件时,通过脚本把客户对该Select控件所包含options的变更,以xml保存到隐藏域。然后在控件的处理CreateChildControls事件时,分析该隐藏域的内容,解析并创建出各ListItem。
以下是解决方案结构图:
在ClientOptionsHolder项目里,ClientOptionsHolder.js包含把options存入隐藏域的客户端脚本。代码如下:
第二个函数的作用是把指定Select的options以被escape编码的xml的格式放入对应隐藏域。
继承的DropDownList代码如下,非常简单:
它的初始化函数中把传入的ListControl的PreRender事件挂接control_PreRender 函数,该函数首先把上面的Javascript资源链接注册到页面,然后在客户端的OnSubmit中添加对保存options到隐藏域的JS函数的调用。最后,把隐藏域输出到客户端。
SetItemsForPostBack()由挂接该ClientOptionsHolder的ListControl在CreateChildControls时调用。它解析客户端隐藏域里面的xml,据此生成所有Items集合。
为了能够使用dll内嵌的资源文件,需要在AssemblyInfo.cs中做如下设置:
[assembly: System.Web.UI.TagPrefix("ZiffWong.Exercise.ControlLibrary", "mstc")]
[assembly: System.Web.UI.WebResource("ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js", "application/x-javascript")]
[assembly: System.Web.UI.WebResource("ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js", "application/x-javascript")]
注意在资源文件ClientOptionsHolders.js前需要加上该控件所在程序集的默认命名空间。程序中对该资源的引用也需要如此处理。
对ListBox的处理和DropDownList一样: