下面,我想向你展示如何把刚才描述的这些例子中所用的单个控件放到一个Web表单上。你可能猜出,我将向你展示如何把这两个例子中的功能封装到它们自己的一个Web控件中。借助于与在常规方法示例中描述的相同的服务器端事件模型,我们可以把所有的行为封装到每一个控件中来实现必要的功能。既然每一个控件都能够控制它自己的状态,那么包含它们的Web表单不必要做任何额外的工作。
到目前为止,一切顺利。你可能问:“问题在哪里?”很好,假定页面开发者在含有大量内容的页面上使用这两个控件,而且每当发生一次重排序或移动,都需要到服务器端的重回寄时,这显然不是一个高效的Web站点要实现的。这正是使用一些JavaScript的原因。
在本例中,你要使用JavaScript代码来存取EnhancedListBox控件中ListBox的内容以便在客户端进行重排序。
在ListMover控件中,JavaScript代码将把项从一个列表移动到另一个列表。其最终结果是一样的,但是不需要进行服务器来回传送,因为不需要触发任何回寄。这样以来,你就可以解决即时响应和不需要回馈的问题。
ASP.net在服务器端生成内容与在客户端生成内容之间有明显的界定。事实上,大部分情况下,这两部分没有关系;因此,问题出现了。其实,一个Web控件只是一个服务器端组件,它负责把HTML生成到浏览器端。的确,标准ASP.NET ListBox控件正是以HTML形式生成一个ListBox(作为一个< select>标签)。
在< select>标签中的< option>子标签可以使用ListBox控件中的Item属性的内容来创建。Item属性在服务器端被填充,而其内容有助于在生成期间构建适当的HTML。这非常类似于生成一个< input>标签的文本框Web控件,而它的Text属性映射到< input>标签的Value属性。每当触发一个到服务器的页面回寄时,ListBox控件的Item属性都被保存到ViewState中,并且在重新生成页面前从ViewState中进行重建。
在EnhancedListBox中进行重排序或在服务器端的ListMover中移动项都非常直接,并且允许支持正常的内置的ViewState机制而不需要我们作任何干扰。但是,当你使用客户端JavaScript添加这一能力来实现它们的功能时,它将破坏ViewState。这些控件并不再转回到服务器端,所以Item集合属性永远不会被保存以便在重新生成时被重载。代之的是,直接在HTML级别上存取生成的< select>标签中的< option>项。你可以借助JavaScript代码移动或重排序控件项;但是,当在页面上再次发生回寄时,你猜发生了什么?在移动(或重排序)开始前,控件的列表项就恢复它们的状态。
我说过,如果功能发生在回寄期间的服务器端,那么,ViewState被保存并且被良好重载,从而使Item集合正确填充。但是,既然你的最终目标是在客户端实现这个功能,那么你就不再需要重新调整Item属性的内容,而是由你依赖的这个属性负责状态存储。现在,你可能会为难了。但是别担心—我有一个解决方案。现在,让我们开始使用必要的客户端脚本代码来开发该控件来实现每一个子控件所需要的功能。然后,我将向你展示如何使它与服务器代码保持重新同步。
在这个控件中,你要把两部分内容添加到现有ASP.NET ListBox控件。首先,添加一个头部—把一个标签放到一个ListBox的上方。然后,把两个按钮添加到ListBox—分别用于向下和向上重排序。
注意 为了简单起见,我在后面所有的代码描述中省略所有的属性部分。
现在,创建一个继承自ListBox控件的新类,如下所示:
- using System.Web.UI;
- using System.Web.UI.WebControls;
- public class EnhancedListBox : ListBox
- {}
如果你编译这部分代码并且把该控件添加到你的工具箱中,那么你将有一个完整功能的ASP.NET ListBox控件副本。我把这个控件作为一个继承控件开发,是因为我想使它具有一个ASP.NET ListBox控件的“占位符”的作用。以后,我再添加其它的属性以实现头部的可见性并支持重排序按钮的打开或关闭。当这些属性全部关闭时,这些控件将在外观与行为上与一个常规ListBox控件一样。然而,你不能使用一个重载的CreateChildControls把控件添加到其上,因为这个函数是用来构建一个控件层次树的。这个ASP.NET ListBox控件被编写为一个生成控件而且直接把它的所有HTML内容绘制到生成引擎;这样以来,你需要在此处“注入”你的内容。你将使用生成控件方法来构建一个标签和两个按钮,并且通过重载Render方法来生成它们。然而,一旦你重载这个方法,你就完全取消了所有的在原始ListBox中的生成内容,而这是不可取的。因此,我想借助于一些小技巧来实现。
【编辑推荐】