无法在UpdatePanel嵌套的WebControl中使用ScriptManager.RegisterStartupScript函数

34

我认为我的问题应该相当简单,但是就是找不到问题所在。这个问题与ScriptManager.RegisterStartupScript有关,这是我以前使用过很多次的东西。

我的场景是:我有一个自定义的Web控件被插入到页面中。该控件(以及其他一两个控件)嵌套在UpdatePanel中。它们被插入到页面上的一个占位符中:

<asp:UpdatePanel ID="pnlAjax" runat="server">
  <ContentTemplate>
    <asp:PlaceHolder ID="placeholder" runat="server">
    </asp:PlaceHolder>
    ...

protected override void OnInit(EventArgs e){
  placeholder.Controls.Add(Factory.CreateControl());
  base.OnInit(e);
}

这是页面上唯一的更新面板。

该控件需要运行一些初始JavaScript才能正确工作。该控件调用:

ScriptManager.RegisterStartupScript(this, GetType(), 
                                    Guid.NewGuid().ToString(), script, true);

我还尝试了以下方法:

ScriptManager.RegisterStartupScript(Page, Page.GetType(), 
                                    Guid.NewGuid().ToString(), script, true);
问题在于脚本在页面首次显示时运行正确,但是在部分回传后不重新运行。我尝试了以下方法:
1.从CreateChildControls调用RegisterStartupScript
2.从OnLoad / OnPreRender中调用RegisterStartupScript
3.使用不同组合的参数来获取前两个参数(在上面的示例中,控件是Page,类型是GetType(),但我尝试过使用控件本身等)
4.尝试使用持续和新id(并不认为这样做会有重大影响);
5.我使用了一些断点,所以已经验证了Register行被正确调用。
唯一我没有尝试的就是将UpdatePanel本身用作Control和Type,因为我不认为Control应该知道UpdatePanel(而且在任何情况下,似乎也没有很好的获取UpdatePanel的方式吗?)。
有人能看出我在上面做错了什么吗?
谢谢 :)
总的来说,回答上面的查询-似乎站位符有些问题,可能会导致ScriptManager.RegisterStartupScript失效。
当我将控件从站位符中取出并直接编写在页面上时,Register脚本可以正常工作(我还将控件本身用作参数)。
ScriptManager.RegisterStartupScript(this, GetType(), Guid.NewGuid().ToString(), script, true);
有人能解释一下为什么向PlaceHolder注入控件会阻止ScriptManager正确注册脚本吗?我猜这可能与动态控件的生命周期有关,但出于自己的知识,是否有正确的过程来解决这个问题?
10个回答

35

我在使用这个时遇到了问题,它在一个用户控件中无法正常工作(在页面上可以正常工作);Button1在updatepanel中,并且scriptmanager位于usercontrol中。

protected void Button1_Click(object sender, EventArgs e)  
{  
    string scriptstring = "alert('Welcome');";  
    ScriptManager.RegisterStartupScript(this, this.GetType(), "alertscript", scriptstring, true);  
}

现在看来,你需要小心前两个参数,它们需要引用你的页面,而不是你的控件。

ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "alertscript", scriptstring, true);

15
我认为您确实应该使用RegisterStartupScript的控件超载
我已经在服务器控件中尝试了以下代码:
[ToolboxData("<{0}:AlertControl runat=server></{0}:AlertControl>")]
public class AlertControl : Control{
    protected override void OnInit(EventArgs e){
        base.OnInit(e);
        string script = "alert(\"Hello!\");";
        ScriptManager.RegisterStartupScript(this, GetType(), 
                      "ServerControlScript", script, true);
    }
}

然后在我的页面中我有:

protected override void OnInit(EventArgs e){
    base.OnInit(e);
    Placeholder1.Controls.Add(new AlertControl());
}

Placeholder1是更新面板中的占位符。该占位符中还有其他控件,包括按钮。

这个行为和你期望的完全一样,每次加载页面或导致更新面板更新时,我都会收到一个提示框显示"Hello"。

你还可以尝试钩入在更新面板请求期间触发的某些页面生命周期事件:

Sys.WebForms.PageRequestManager.getInstance()
   .add_endRequest(EndRequestHandler);

PageRequestManager endRequestHandler事件在每次更新面板完成其更新时触发 - 这将允许您调用一个方法来设置您的控件。

我唯一的其他问题是:

  • 你的脚本实际上在做什么?
  • 你可以在页面底部(即关闭 </form> 标签之前)看到脚本吗?
  • 您是否尝试在启动脚本中放置几个“alert(“Here”);”调用以查看它是否被正确调用?
  • 您是否尝试过Firefox和Firebug - 它是否报告任何脚本错误?

嗨Ben,感谢你的回答。目前脚本只是触发一个警报,没有其他操作。它是一个网格控件,继承自datagrid。我通常会使用Firefox/Bug,但在这种情况下,我正在使用仅限IE的应用程序(不是我的选择),无法在FF中访问屏幕。使用IE Dev工具栏,我可以检查页面,但脚本在postback后没有重新注册。我喜欢PageRequestManager的想法,尽管脚本不容易暴露给页面作为处理程序调用。我喜欢这些想法,并将进一步调查,谢谢。 - Chris

10

当您调用ScriptManager.RegisterStartupScript时,"Control"参数必须是在UpdatePanel中将要更新的控件。你需要将它更改为:

ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(), script, true);

是的 - 我已经尝试使用控件本身,它嵌套在UpdatePanel中。该控件被插入到占位符中,但我认为这应该没问题? - Chris

1
解决方案是将脚本放在外部js文件中(称为“yourDynamic.js”),并每次刷新updatepanel时重新注册该文件。
我在updatepanel_prerender事件中使用了这个方法:
ScriptManager.RegisterClientScriptBlock(UpdatePanel1, UpdatePanel1.GetType(), "UpdatePanel1_PreRender", _
                   "<script type='text/javascript' id='UpdatePanel1_PreRender'>" & _
                   "include('yourDynamic.js');" & _
                   "removeDuplicatedScript('UpdatePanel1_PreRender');</script>" _
                   , False)

在页面或其他包含文件中,您需要使用以下JavaScript代码:
// Include a javascript file inside another one.
function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].getAttribute('src'))
        {
            if(scripts[x].getAttribute('src').indexOf(filename) != -1)
            {
                head.removeChild(scripts[x]);
                break;
            }
        }
    }

    script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';
    head.appendChild(script)
}

// Removes duplicated scripts.
function removeDuplicatedScript(id)
{
    var count = 0;
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    var firstScript;
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].getAttribute('id'))
        {
            if(scripts[x].getAttribute('id').indexOf(id) != -1)
            {
                if (count == 0)
                {
                    firstScript = scripts[x];
                    count++;
                }
                else
                {
                    head.removeChild(firstScript);
                    firstScript = scripts[x];
                    count = 1;
                }
            }
        }
    }
    clearAjaxNetJunk();
}
// Evoids the update panel auto generated scripts to grow to inifity. X-(
function clearAjaxNetJunk()
{
    var knowJunk = 'Sys.Application.add_init(function() {';
    var count = 0;
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    var firstScript;
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].textContent)
        {
            if(scripts[x].textContent.indexOf(knowJunk) != -1)
            {
                if (count == 0)
                {
                    firstScript = scripts[x];
                    count++;
                }
                else
                {
                    head.removeChild(firstScript);
                    firstScript = scripts[x];
                    count = 1;
                }
            }
        }
    }
}

挺酷的,哈哈哈。我之前发布的一部分内容在这里 here

希望这有所帮助... :)


嗯,有趣的机制 - 我可以看出在一些情况下它会很有用。不确定这是否完全解决了我的问题,因为通过脚本管理器插入的任何js都被UpdatePanel忽略了 - 我甚至无法运行alert('hello world');!至少不能在占位符中嵌入它 :( 不过我会试一下的,总是乐意被证明是错误的 :) - Chris
请记住,这里的插入实际上是由JavaScript完成的,这就是它如此动态的原因。如果可以,请告诉我它是否有效。 - Lucas
哦... 还记得调用 RegisterClientScriptBlock 应该在 updatepanel 的 prerrender 事件里面... :) - Lucas
1
嗨Lucas-这就是我的问题-自定义控件位于UpdatePanel内,自定义控件尝试注册该块,但UpdatePanel无法识别它-因此没有运行任何JavaScript。我无法将JavaScript从控件中拉出并添加到页面中-这将消除封装行为的优势。 - Chris

1

不要使用 GUID 作为键

ScriptManager.RegisterClientScriptBlock(this.Page, typeof(UpdatePanel) 
       Guid.NewGuid().ToString(), myScript, true);

如果你想做那件事,调用类似这样的函数

 public static string GetGuidClear(string x)
 {
      return x.Replace("-", "").Replace("0", "").Replace("1", "")
              .Replace("2",  "").Replace("3", "").Replace("4", "")
              .Replace("5", "").Replace("6", "").Replace("7", "")
              .Replace("8", "").Replace("9", "");
 }

1

我遇到了一个关于Page.ClientScript.RegisterStartUpScript的问题 - 我没有使用更新面板,但是控件被缓存了。这意味着我必须将脚本插入到Literal(或者可以使用PlaceHolder),以便在从缓存中呈现时包含脚本。

类似的解决方案可能也适用于您。


谢谢 - 我会调查字符串字面量,可能是一个好的解决方法。我正在使用不同的插入技术,因为我正在使用 System.Web.Ui.ScriptManager 的静态方法,而不是 Page.ClientScript 机制。 - Chris

0
ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(),script,  true );

在ScriptManager.RegisterStartupScript的结尾处设置"true"参数值将在您的页面内添加一个JavaScript标签:

<script language='javascript' defer='defer'>your script</script >

如果值为“false”,它将仅注入脚本而不包含--script--标签。

0

对我而言有效的方法是在注册时将类型指定为UpdatePanel,像这样:

ScriptManager.RegisterClientScriptBlock(this.Page, typeof(UpdatePanel) Guid.NewGuid().ToString(), myScript, true);

0

我尝试了很多方法,最终发现最后一个参数必须为false,并且您必须将<SCRIPT>标签添加到JavaScript中:

string script = "< SCRIPT >alert('hello!');< /SCRIPT>";

ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), key, script, **false**);

2
将最后一个参数设置为true会自动添加脚本标签。 - cjk

0
有时候当脚本存在一些语法错误时,它不会触发,请确保脚本和JavaScript语法正确。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接