注册起动脚本,ASP.NET AJAX的一项重要功能!
最近的项目中一直在使用Atlas July CTP,自从Atlas正式更名后,连续推出了Beta和Beta2两个版本,但是我一直在观望,原因就是Beta版本不稳定而且升级太麻烦了。一日偶然看到了杨丹的这篇随笔,突然发现原来ScriptManager可以注册在客户端部分刷新的UpdatePanel中注册启动后执行的JavaScript!这可是困扰了我很长时间的一个问题!这样不但可以在使用UpdatePanel的情况下使用Javascript弹出对话框,也可以在开发使用Javascript脚本的服务器控件的时候,使控件的起动脚本得以执行,这样原来的和UpdatePanel不兼容的控件可以很容易的改为AJAX enabled^_^。
不过,令人不解的是不知道处于什么考虑,RegisterStartupScript函数竟然实现为了类的静态函数,可是没有ScriptManager的UpdatePanel更本不能执行啊,这样还需要多打几个字!另外,需要注意的是第一个参数是UpdatePanel的实例,如果在页面中有多个UpdatePanel,如果每个UpdatePanel的UpdateMode都是“always”[默认值]的话,那么你使用那个UpdatePanel的实例作为参数都可以;如果每个UpdaePanel的UpdateMode=conditional,那么你必须使用正在更新的那个UpdatePanel作为参数,这样脚本才能起作用。下面是我作的一个简单的示例:
(本来不想让这简单的代码占地方,可是有网友反映IE7看不了折叠代码,只好手动去掉了:))
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" EnablePartialRendering="true" runat="server">
</asp:ScriptManager>
<br />
<asp:updatepanel id="UpdatePanel1" UpdateMode="conditional" runat="server"><ContentTemplate>
<asp:TextBox id="TextBox1" runat="server" ></asp:TextBox> <asp:LinkButton id="LinkButton1" runat="server" OnClick="LinkButton1_Click">LinkButton</asp:LinkButton>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="LinkButton1" />
</Triggers>
</asp:updatepanel>
<asp:UpdatePanel ID="UpdatePanel2" RenderMode="block" UpdateMode="always" runat="server">
<ContentTemplate>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton2_Click">LinkButton</asp:LinkButton>
</ContentTemplate>
</asp:UpdatePanel>
<br />
<div>
<br />
<asp:updateprogress id="UpdateProgress1" runat="server"><ProgressTemplate>
Please waiting, retrieving data from server
</ProgressTemplate>
</asp:updateprogress>
</div>
</form>
</body>
</html>
using System;
using System.Data;
using System.Configuration;
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 _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(1000);
TextBox1.Text = DateTime.Now.ToLongTimeString();
TextBox2.Text = TextBox1.Text;
string js = "alert('ok button1 clicked!')";
Microsoft.Web.UI.ScriptManager.RegisterStartupScript(UpdatePanel2, this.GetType(), "btn1clicked", js, true);
}
protected void LinkButton2_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(900);
TextBox2.Text = DateTime.Now.ToLongTimeString();
TextBox1.Text = TextBox2.Text;
string js = "alert('ok button 2 clicked!')";
Microsoft.Web.UI.ScriptManager.RegisterStartupScript(UpdatePanel2, this.GetType(), "btn2clicked", js, true);
}
}
BTW,我在使用时发现一个问题,不知道是个Bug还是我使用不当,我在调试中发现UpdatePanel.IsInPartialRendering的值始终是false!希望有高人指点一下:)。
补充,应网友要求添加函数FindUpdatePanel的代码:
不过,令人不解的是不知道处于什么考虑,RegisterStartupScript函数竟然实现为了类的静态函数,可是没有ScriptManager的UpdatePanel更本不能执行啊,这样还需要多打几个字!另外,需要注意的是第一个参数是UpdatePanel的实例,如果在页面中有多个UpdatePanel,如果每个UpdatePanel的UpdateMode都是“always”[默认值]的话,那么你使用那个UpdatePanel的实例作为参数都可以;如果每个UpdaePanel的UpdateMode=conditional,那么你必须使用正在更新的那个UpdatePanel作为参数,这样脚本才能起作用。下面是我作的一个简单的示例:
(本来不想让这简单的代码占地方,可是有网友反映IE7看不了折叠代码,只好手动去掉了:))
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" EnablePartialRendering="true" runat="server">
</asp:ScriptManager>
<br />
<asp:updatepanel id="UpdatePanel1" UpdateMode="conditional" runat="server"><ContentTemplate>
<asp:TextBox id="TextBox1" runat="server" ></asp:TextBox> <asp:LinkButton id="LinkButton1" runat="server" OnClick="LinkButton1_Click">LinkButton</asp:LinkButton>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="LinkButton1" />
</Triggers>
</asp:updatepanel>
<asp:UpdatePanel ID="UpdatePanel2" RenderMode="block" UpdateMode="always" runat="server">
<ContentTemplate>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton2_Click">LinkButton</asp:LinkButton>
</ContentTemplate>
</asp:UpdatePanel>
<br />
<div>
<br />
<asp:updateprogress id="UpdateProgress1" runat="server"><ProgressTemplate>
Please waiting, retrieving data from server
</ProgressTemplate>
</asp:updateprogress>
</div>
</form>
</body>
</html>
using System;
using System.Data;
using System.Configuration;
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 _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(1000);
TextBox1.Text = DateTime.Now.ToLongTimeString();
TextBox2.Text = TextBox1.Text;
string js = "alert('ok button1 clicked!')";
Microsoft.Web.UI.ScriptManager.RegisterStartupScript(UpdatePanel2, this.GetType(), "btn1clicked", js, true);
}
protected void LinkButton2_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(900);
TextBox2.Text = DateTime.Now.ToLongTimeString();
TextBox1.Text = TextBox2.Text;
string js = "alert('ok button 2 clicked!')";
Microsoft.Web.UI.ScriptManager.RegisterStartupScript(UpdatePanel2, this.GetType(), "btn2clicked", js, true);
}
}
补充,应网友要求添加函数FindUpdatePanel的代码:
FindUpdatePanel的代码
/// <summary>
/// 查找给定ID的UpdatePanel
/// </summary>
/// <param name="upid">UpdatePanel的ID</param>
/// <returns></returns>
public UpdatePanel FindUpdatingPanel(ControlCollection ca, string upid)
{
foreach (Control c in ca)
{
if (c is UpdatePanel)
{
UpdatePanel up = (UpdatePanel)c;
if (up.ID == upid)
return up;
}
if (c.Controls.Count > 0) // recursive call
{
UpdatePanel cup = FindUpdatingPanel(c.Controls, upid);
if (cup != null)
return cup;
}
}
return null;
}
public UpdatePanel FindUpdatingPanel(ControlCollection ca)
{
foreach (Control c in ca)
{
if (c is UpdatePanel)
{
UpdatePanel up = (UpdatePanel)c;
//if (up.IsInPartialRendering) //******** 在Beta2中好像状态不对,只能返回第一个UpdatePanel
return up;
}
if (c.Controls.Count > 0)
{
UpdatePanel cup = FindUpdatingPanel(c.Controls);
if (cup != null)
return cup;
}
}
return null;
}
/// <summary>
/// 查找给定ID的UpdatePanel
/// </summary>
/// <param name="upid">UpdatePanel的ID</param>
/// <returns></returns>
public UpdatePanel FindUpdatingPanel(ControlCollection ca, string upid)
{
foreach (Control c in ca)
{
if (c is UpdatePanel)
{
UpdatePanel up = (UpdatePanel)c;
if (up.ID == upid)
return up;
}
if (c.Controls.Count > 0) // recursive call
{
UpdatePanel cup = FindUpdatingPanel(c.Controls, upid);
if (cup != null)
return cup;
}
}
return null;
}
public UpdatePanel FindUpdatingPanel(ControlCollection ca)
{
foreach (Control c in ca)
{
if (c is UpdatePanel)
{
UpdatePanel up = (UpdatePanel)c;
//if (up.IsInPartialRendering) //******** 在Beta2中好像状态不对,只能返回第一个UpdatePanel
return up;
}
if (c.Controls.Count > 0)
{
UpdatePanel cup = FindUpdatingPanel(c.Controls);
if (cup != null)
return cup;
}
}
return null;
}