注册起动脚本,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>
                    
&nbsp;</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的代码
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;
    }

posted @ 2006-11-20 00:28 大剑师 阅读(3279) 评论(13)  编辑 收藏 网摘 所属分类: AJAX

  回复  引用  查看    
#1楼2006-11-20 00:35 | Dflying Chen      
你说的这个功能在CTP版的Atlas中可以使用下述方法注册局部回送后页面中的JavaScript:
ClientScript.RegisterStartupScript(GetType(), "scriptName", "alert('Time updated!')", true);

现在的Beta只不过是改了个地方而已。

事实上,这样的改动使得现有的控件和UpdatePanel结合变得更加困难了,别说第三方的控件,哪怕是Menu、Tree等ASP.NET内建的控件都无法在Beta版的UpdatePanel中使用。

  回复  引用  查看    
#2楼2006-11-20 07:51 | 命运有自己的梦!      
咦,好像不对啊,我的Menu在UpdatePanel中工作很正常啊!
  回复  引用  查看    
#3楼[楼主]2006-11-20 08:48 | 大剑师      
@Dflying Chen
你所说的却不敢苟同,我以前一直象你所说的这样做的,可是我的Alert从来没有出现过!

  回复  引用    
#4楼2006-11-20 10:07 | crabo[未注册用户]
@大剑师
Dflying Chen 说的自然是对的. 查查官方论坛即知.

倒是ScriptManager的RegXXX方法实在没意思, 我根本没法提供目的刷新区的控件ID

不过将会提供一种全局的RegXXX的方法, 只好等下个版本了

  回复  引用  查看    
#5楼[楼主]2006-11-20 11:19 | 大剑师      
@Dflying Chen
请看我的BasePage中的这个函数,我以前是这样用的
public void ShowMessage(string msg)
        
{
            StringBuilder sb 
= new StringBuilder();
            msg 
= PrepareScriptString(msg);
            sb.Append(
"<script>");
            sb.Append(
"alert('" + msg + "')");
            sb.Append(
"</script>");
            ClientScript.RegisterStartupScript(
this.GetType(), "ShowMessage" + msg.GetHashCode().ToString(), sb.ToString());
        }
结果在UpdatePanel中部分刷新后无法显示Alert消息,现在改为
/// <summary>
        
/// 在客户端显示一个JavaScript脚本的提示框
        
/// </summary>
        
/// <param name="msg">显示的消息</param>

        public void ShowMessage(string msg)
        
{
            ShowMessage(msg,
string.Empty);
        }

        
/// <summary>
        
/// 在客户端显示一个JavaScript脚本的提示框,用于指定ID的UpdateControl控件〔当部分刷新时〕
        
/// </summary>
        
/// <param name="msg">显示的消息</param>
        
/// <param name="upid">UpdateControl控件的id</param>

        public void ShowMessage(string msg,string upid)
        
{
            StringBuilder sb 
= new StringBuilder();
            msg 
= PrepareScriptString(msg);
            sb.Append(
"<script>");
            sb.Append(
"alert('" + msg + "')");
            sb.Append(
"</script>");
            ScriptManager sm 
= ScriptManager.GetCurrent(this);
            
if (sm != null//// Yes , It's using ScriptManager and UpdatePanel
            {
                
if (sm.IsInAsyncPostBack)
                
{
                    UpdatePanel up;
                    
if (string.IsNullOrEmpty(upid))
                        up 
= FindUpdatingPanel(this.Controls);
                    
else
                        up 
= FindUpdatingPanel(this.Controls, upid);
                    
if (up != null)
                    
{
                        ScriptManager.RegisterStartupScript(up, 
this.GetType(), "ShowMessage" + msg.GetHashCode().ToString(), sb.ToString(), false);
                        
return;
                    }

                }

            }

            
//// else use the page's clientscriptmanager
            ClientScript.RegisterStartupScript(this.GetType(), "ShowMessage" + msg.GetHashCode().ToString(), sb.ToString());
        }
在Beta2中正常使用,请指点。

  回复  引用    
#6楼2006-11-20 11:20 | moslem[未注册用户]
Dlying Chen

确认在 Partial Rendering 时 ,你的代码:

ClientScript.RegisterStartupScript(GetType(), "scriptName", "alert('Time updated!')", true);

也能使用?我以前测试一直不成功,后来用如下代码才能发挥作用:

Page.ClientScript.RegisterStartupScript(this.GetType(), "scriptname", "Sys.Application.load.add (jsfun);\n", true); //jsfun 是一个 java scription function,需要预先定义

在 beta 版本才通过楼主的方法成功设置 jsfun ,无需再 Sys.Application.load.add...


  回复  引用  查看    
#7楼2006-11-20 22:01 | Ring      
学习... ...
  回复  引用    
#8楼2006-11-22 11:51 | wg[未注册用户]
老大,能不能将代码段设为默认显示,我用IE7.0看不了代码,出脚本错。
学习......

  回复  引用  查看    
#9楼[楼主]2006-11-22 13:25 | 大剑师      
@wg
手工修改了,相当费尽啊:)

  回复  引用    
#10楼2007-05-07 15:15 | YJ[未注册用户]
那个 FindUpdatingPanel 是自己写的方法吧?

我的代码是
UpdatePanel m_UpdatePanel = ((UpdatePanel)this.Parent.FindControl(m_UpdatePanelID));

ScriptManager.RegisterStartupScript((Control)m_UpdatePanel, GetType(), "ExcScript", "<script>" + ViewState["GridViewID"].ToString() + "ChangeControlEnabled(0)</script>", false);

但是一直提示说The control must be in the control tree of a page.
请教

  回复  引用    
#11楼2007-07-04 13:57 | orange[未注册用户]
FindUpdatingPanel 方法是什么呢?
麻烦给下代码,参考一下吧,谢谢。

  回复  引用  查看    
#12楼[楼主]2007-07-06 11:41 | 大剑师      
@orange
不好意思,没看见。其实很简单:
public static object FindScriptManager(Page p)
{
foreach (DictionaryEntry entry in p.Items)
{
if (entry.Key.ToString().IndexOf("System.Web.UI.ScriptManager") >= 0)
{
return entry.Value;
}
}
return null;
}


  回复  引用    
#13楼2007-08-03 18:51 | lost[未注册用户]
PrepareScriptString 这个是做什么的 怎么报错啊



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 565524




相关文章:

相关链接: