
第4章ASP.NET AJAX提高篇
4.1 动态加载的课题
前一章中,已经展示了如何动态加载UserControl至UpdatePanel控件中,但这只是一段旅程的序曲,动态加载的复杂性远超过你的想象,一般来说,动态加载控件至UpdatePanel控件中并不是最大的问题,如何维持载入的控件能正常运作才是最大的课题,就如同动态加载控件至PlaceHolder或Panel控件中一样,在下次Postback发生前,我们必须负责重载已加载的控件,否则该控件的事件将无法正常递送。请照以下的步骤来建立一个Web Site。
1. 建立一个AJAX-Enabled的Web Site,命名为AjaxDemo2。
2. 建立一个UserControl,命名为WebUserControl2.ascx。
3. 在UserControl中放入一个Calender控件。
4. 建立一个新网页,命名为DynamicLoadUserControl.aspx。
5. 在页面中放入一个ScriptManager控件。
6. 在页面中放入一个UpdatePanel控件。
7. 将UpdatePanel1控件的UpdateMode设为Conditional。
8. 放一个Button控件至UpdatePanel控件中。
9. 在Button的Click事件中,键入程序4-1的代码。
程序4-1
Samples\4\AjaxDemo2\DynamicLoadUserControl.aspx.cs protected void Button1_Click(object sender, EventArgs e) { if (UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl1") == null) { Control c = LoadControl("WebUserControl2.ascx"); c.ID = "Dynamic_UserControl_Hidden1"; UpdatePanel1.ContentTemplateContainer.Controls.Add(c); } }
执行程序并点击Button后,Calender如预期般显示,但若再点击某个日期后,Calender便立刻消失,这与动态加载控件至PlaceHolder及Panel控件的情况一样,因为点击日期后并未触发Button的Click事件,所以也就没有加载UserControl的动作发生,自然UserControl也不可能显示在网页上。那么该如何做才能正常呢?与使用PlaceHolder及Panel动态加载控件的解法相同,我们必须建立一个标记,当Button被点击时设定这个标记,这样在下次Postback发生时,即可用此标记来判定是否要加载UserControl,担任此标记最好的演员便是Hidden Field。请照以下的步骤来修改此例。
1. 删除Button的Click事件中的程序代码。
2. 在网页源码中放入Hidden Field,如程序4-2之粗体字所示。
3. 在此网页的.cs中加入程序4-3的代码。
程序4-2
Samples\4\AjaxDemo2\DynamicLoadUserControl.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile= "DynamicLoadUserControl.aspx.cs" Inherits="DynamicLoadUserControl" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> </div> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <input type=hidden ID="Dynamic_UserControl_Hidden1" runat=server/> <asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="ShowControl();" OnClick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html>
程序4-3
Samples\4\AjaxDemo2\DynamicLoadUserControl.aspx.cs using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class DynamicLoadUserControl : System.Web.UI.Page { protected void Page_Init(object sender, EventArgs e) { //从送来的参数中,判断UserControl是否已经加载 if (Request.Params["Dynamic_UserControl_Hidden1"] == "true") LoadDynamicUserControl(); } //动态加载UserControl private void LoadDynamicUserControl() { if (UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl1") == null) { Control c = LoadControl("WebUserControl2.ascx"); c.ID = "Dynamic_UserControl1"; //取得位于UserControl中的Hidden Field,并将其值设为True, //代表UserControl已经加载 HtmlInputHidden hidden = (HtmlInputHidden) UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl_Hidden1"); hidden.Value = "true"; UpdatePanel1.ContentTemplateContainer.Controls.Add(c); } } protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { //送上来的参数中的Hidden Field表示UserControl已载入, //将载入的UserControl删除 if (Request.Params["Dynamic_UserControl_Hidden1"] == "true") { UpdatePanel1.ContentTemplateContainer.Controls.Remove( UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl1")); HtmlInputHidden hidden = (HtmlInputHidden) UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl_Hidden1"); hidden.Value = "false"; } else LoadDynamicUserControl(); } }
完成后执行程序,点击Button后Calendar显示,此次你能正常地点击任何日期,而不会使Calendar消失,如图4-1所示。

图4-1
同时再次点击Button后,Calendar也会消失,这是借助Hidden Field的帮助。除了使用Hidden Field之外,我们也可以利用VIEWSTATE来达到同样的效果,这个方法的好处是不需要另一个Hidden Field的帮助,程序代码会显得较简洁、直观,如程序4-4所示。
程序4-4
Samples\4\AjaxDemo2\DynamicLoadUserControlWithViewState.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="DynamicLoadUserControlWithViewState.aspx.cs" Inherits="DynamicLoadUserControlWithViewState" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> </div> <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode= "Conditional"> <ContentTemplate> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> Samples\4\AjaxDemo2\DynamicLoadUserControlWithViewState.aspx.cs using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class DynamicLoadUserControlWithViewState : System.Web.UI.Page { private bool ControlIsLoaded { get { object o = ViewState["ControlIsLoaded"]; return (o == null ? false : (bool)o); } set { ViewState["ControlIsLoaded"] = value; } } private void LoadDynamicUserControl() { if (UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl1") == null) { Control c = LoadControl("WebUserControl2.ascx"); c.ID = "Dynamic_UserControl1"; ControlIsLoaded = true; UpdatePanel1.ContentTemplateContainer.Controls.Add(c); } } protected void Page_Load(object sender, EventArgs e) { if (ControlIsLoaded) LoadDynamicUserControl(); } protected void Button1_Click(object sender, EventArgs e) { if (ControlIsLoaded) { UpdatePanel1.ContentTemplateContainer.Controls.Remove( UpdatePanel1.ContentTemplateContainer.FindControl( "Dynamic_UserControl1")); ControlIsLoaded = false; } else LoadDynamicUserControl(); } }
截至目前,我们已经看过两种动态显示控件的方式,第一种较为简单、不需要设计师写太多的程序代码,第二种较为复杂,需要设计师写较多的的程序代码,两者间性能的差距在于初次加载网页时,第一种不管如何都会建立欲动态显示的控件,虽然将其Visible设为False能减轻初次载入网页的负担,但毕竟控件还是加载了,对性能多少都有一些影响;第二种则是完全动态式的加载,初期并未建立该控件,而是需要时才建立,当网页上有多种这类控件时,这种做法特别有效率。