决战.NET
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.8 包含外部的JavaScript文件

理论上,UpdatePanel控件中可放入大部分的ASP.NET控件,这也包含了使用者自定义的UserControl控件,但是这有个异常情况,当该UserControl中含有JavaScript程序代码,且被动态加载至UpdatePanel控件中时会引发一些问题。呃!动态加载UserControl至UpdatePanel中,这不是跟前面提及的动态加载控件一样吗?不过这次我们采用另一种方式,用完全式的动态加载,也就是说一开始UserControl并不是放在UpdatePanel控件中的,而是在使用者点击按钮后,由程序动态加载的。请照以下的步骤来创建一个新网页。

1. 创建一个UserControl,取名为WebUserControl.ascx,程序代码如程序3-18所示。

2. 创建一个新网页,命名为UseUserControl.aspx。

3. 在页面中放入ScriptManager控件。

4. 在页面中放入UpdatePanel控件。

5. 将UpdatePanel1控件的UpdateMode设为Conditional。

6. 放此WebUserControl控件至UpdatePanel控件中。

程序3-18

    Samples\3\AjaxDemo1\WebUserControl.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile=
      "WebUserControl.ascx.cs" Inherits="WebUserControl" %>
    <script language=javascript>
      function showMessage(msg)
      {
          alert('Message:'+msg);
      }
    </script>
    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"
    OnClientClick="showMessage('Test')" />

运行程序后,点击Button后便可看到信息,如图3-15所示。

true

图3-15

这个例子证明了UserControl可以放在UpdatePanel控件中,接下来就是将此例子改成动态加载UserControl。请照以下步骤做。

1. 创建一个新网页,命名为DynamicLoadUserControl1.aspx。

2. 在页面中放入一个ScriptManager控件。

3. 在页面中放入一个UpdatePanel控件。

4. 放一个Button控件至UpdatePanel控件中。

5. 在Button的Click事件中键入程序3-19的代码。

程序3-19

    Samples\3\DynamicLoadUserControl1.aspx
    protected void Button1_Click(object sender, EventArgs e)
    {
            if (UpdatePanel1.ContentTemplateContainer.FindControl("DynamicControl1")
                == null)
            {
                  Control c = Page.LoadControl("WebUserControl.ascx");
                  c.ID = "DynamicControl1";
                  UpdatePanel1.ContentTemplateContainer.Controls.Add(c);
            }
    }

运行程序并点击Button后,便可看到该UserControl控件已被载入,这是无刷新动态加载UserControl的基础,如图3-16所示。

true

图3-16

但若点击右方的Button后,会看到报错信息,如图3-17所示。

true

图3-17

这是为什么呢?是因为UpdatePanel控件的处理机制。只要异步刷新的内容含有JavaScript程序代码,这段程序代码是无法被绘制到现行网页中的。别误会!我指的是明白声明成<script>...</script>的程序代码,以及<script src....></script>类的程序代码,不包含直接于HTML元素中所设定的程序代码,例如onclick='alert(...)'类的程序代码是被允许的,但是若这类程序代码调用其他自定义于以上两种区段的函数时,同样是行不通的!就如同本例中,showMessage是声明于<script>区段中的,虽然onclick可以正常绘制,但因为所调用的JavaScript函数未被绘制,所以引发调用函数不存在的错误。这个特性也告诉了我们,UpdatePanel控件中所能动态加载的ASP.NET控件类型,只要该ASP.NET控件会输出以上两种区段JavaScript程序代码的,便会引发错误,典型的控件便是TreeView!那这该如何解决呢?这得视欲载入的控件而定了。TreeView控件是很难从外部修改,令其可动态加载至UpdatePanel中的,不过我们的UserControl没那么复杂,只要运用ScriptManager控件的Scripts属性,加载指定的JavaScript程序文件即可。请照着下面的步骤做。

1. 创建一个新网页,命名为DynamicLoadUserControl2.aspx。

2. 在页面中放入一个ScriptManager控件。

3. 在页面中放入一个UpdatePanel控件。

4. 放一个Button控件至UpdatePanel控件中。

5. 在Button的Click事件中键入程序3-20的代码。

6. 创建一个UserControl,命名为WebUserControl1.ascx,内容如程序3-21所示。

7. 创建一个JavaScript文件,命名为JScript.js,内容如程序3-22所示。

8. 点击ScriptManager控件的Scripts属性,加入引用JScript.js文件,如图3-18所示。

程序3-20

    Samples\3\DynamicLoadUserControl1.aspx
    protected void Button1_Click(object sender, EventArgs e)
    {
            if (UpdatePanel1.ContentTemplateContainer.FindControl("DynamicControl1")
                == null)
            {
                Control c = Page.LoadControl("WebUserControl1.ascx");
                c.ID = "DynamicControl1";
                UpdatePanel1.ContentTemplateContainer.Controls.Add(c);
            }
    }

程序3-21

    Samples\3\AjaxDemo1\WebUserControl1.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile=
      "WebUserControl1.ascx.cs" Inherits="WebUserControl1" %>
    </script>
    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"
    OnClientClick="showMessage('Test')" />

程序3-22

    function showMessage(str)
    {
      alert(str);
    }
    //很重要,所有通过ScriptReference并以Path方式加载的.js文件中都必须包含这段程序代码,
    //告诉ASP.NET AJAX这个.js已经完全加载完毕.
      if(Sys && Sys.Application) { Sys.Application.notifyScriptLoaded(); }

在程序3-22 的代码末行,调用了Sys.Application.notifyScriptLoaded函数,此举目的在于告诉ASP.NET AJAX的Script Loader这个JavaScript程序文件已经完全加载完毕。

true

图3-18

这里的Path指的是JScript.js的位置,若放于其他目录中,例如scripts目录中,即设为“scripts/JScript.js”,指定的文件将会于此网页初次绘制时便被载入,以本例来说,原本动态加载时是无法加载JavaScript的,但是只要这样设置后,该JavaScript早就已经被加载,所以本例便可运行了。除了载入真实的JavaScript文件外,ScriptManager控件也允许加载Assembly中的Script资源,这部分将于后面ASP.NET AJAX延展性一节中讨论。完成并运行本例后,便可发现其已能正常运行了,如图3-19所示。

true

图3-19

Scripts中指定的JavaScript文件的加载位置会受到ScriptManager之LoadScriptsBeforeUI属性值影响,默认此属性值为True,也就是于UI控件载入前载入这些Scripts,若此值为False,那么Scripts便会于UI控件加载后加载,这会造成什么影响呢?当此值为False时,Scripts载入于UI控件加载之后,因此若Script中有全局程序代码时,且这些程序代码中企图以$get函数取得UI控件的HTML元素对象时,将可以正常运行。反之若此值为True,加载Script时UI控件尚未完全加载,所以在全局程序代码中调用$get函数时便会回传NULL。举个较实际的例子,若将程序3-22改成如程序3-23,那么在LoadScriptsBeforeUI值为True时会产生错误,为False则不会。

程序3-23

    function showMessage(str)
    {
      alert(str);
    }
    var p = $get('Button1').value;
    //for every script include at scriptReference with path of ScriptManager/
      ScriptManagerProxy,
    //you must add below code to notify Script is loaded,or you may get Sys.
      ScriptLoadFailedException Exception;.
    //if your scriptReference is with Assembly,you can set NotifyScriptLoaded to
      true,
    //ScriptManager will add notifyScriptLoaded code for your script code.
    if(Sys && Sys.Application) { Sys.Application.notifyScriptLoaded(); }