无法让嵌套在 UpdatePanel 中的 WebControl 中的 ScriptManager.RegisterStartupScript 工作

Posted

技术标签:

【中文标题】无法让嵌套在 UpdatePanel 中的 WebControl 中的 ScriptManager.RegisterStartupScript 工作【英文标题】:Can't get ScriptManager.RegisterStartupScript in WebControl nested in UpdatePanel to work 【发布时间】:2010-10-22 14:19:48 【问题描述】:

我遇到了我认为应该是一个相当简单的问题,但是对于我的生活,我看不到我的问题。问题与ScriptManager.RegisterStartupScript有关,我之前用过很多次。

我的情况是我有一个已插入页面的自定义 Web 控件。控件(以及一两个其他控件)嵌套在 UpdatePanel 中。它们被插入到页面上的 PlaceHolder 上:

<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);

问题是脚本在页面第一次显示时运行正确,但在部分回发后没有重新运行。我尝试了以下方法:

    从 CreateChildControls 调用 RegisterStartupScript 从 OnLoad / OnPreRender 调用 RegisterStartupScript 对前两个参数使用不同的参数组合(在上面的示例中,Control 是 Page,Type 是 GetType(),但我尝试过使用控件本身等)。 我尝试过使用持久 ID 和新 ID(并不是说我认为这两种方式都会产生重大影响)。 我使用了几个断点,因此验证了 Register 行被正确调用。

我唯一没有尝试过的是使用 UpdatePanel 本身作为控件和类型,因为我不认为控件应该知道更新面板(无论如何似乎没有一个好的方法获取更新面板?)。

谁能看到我在上面做错了什么?

谢谢:)


好吧,回答上面的问题 - 它看起来好像占位符以某种方式弄乱了 ScriptManager.RegisterStartupScript。

当我将控件从占位符中拉出并将其直接编码到页面上时,Register 脚本可以正常工作(我也将控件本身用作参数)。

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

谁能解释一下为什么注入到 PlaceHolder 上的控件会阻止 ScriptManager 正确注册脚本?我猜这可能与动态控件的生命周期有关,但如果有正确的上述过程,我会很感激(据我所知)。

【问题讨论】:

【参考方案1】:

我在用户控件中使用它时遇到了问题(在一个页面中这很好用); Button1 在updatepanel 内,scriptmanagerusercontrol 上。

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);

【讨论】:

【参考方案2】:

我认为您确实应该使用 RegisterStartupScript 的 Control overload。

我在服务器控件中尝试了以下代码:

[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 是更新面板中的占位符。占位符中有几个其他控件,包括按钮。

这完全符合您的预期,每次加载页面或导致更新面板更新时,我都会收到一条提示“您好”的警报。

您可以查看的另一件事是挂钩在更新面板请求期间触发的一些页面生命周期事件:

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

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

我唯一的其他问题是:

您的脚本实际上在做什么? 大概您可以在页面底部的 html 中看到脚本(就在结束 标记之前)? 您是否尝试过放置一些“alert("Here");"在您的启动脚本中调用以查看它是否被正确调用? 您是否尝试过 Firefox 和 Firebug - 是否报告任何脚本错误?

【讨论】:

嗨,本,感谢您的回答。目前脚本只是触发警报,仅此而已。它是一个网格控件,继承了datagrid。我通常会使用 Firefox/Bug,但在这种情况下,我正在使用仅限 IE 的应用程序(不是我的选择),无法进入 FF 中的屏幕。使用 IE Dev 工具栏我可以检查页面,但脚本没有在回发时重新注册。我喜欢 PageRequestManager 的想法,尽管脚本不容易暴露给页面以作为处理程序调用。我喜欢这些想法,并将使用这些想法进行进一步调查,谢谢【参考方案3】:

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

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

【讨论】:

是的 - 我已经尝试使用控件本身,它嵌套在 UpdatePanel 中。控件插入到占位符中,但我相信这应该可以吗?【参考方案4】:

解决方案是将脚本放在外部 js 文件中(我们称为“yourDynamic.js”),并在每次刷新更新面板时重新注册 de 文件。

我在 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;
                
            
        
    

很酷,啊...jejeje 这部分是我前段时间发的here。

希望对您有所帮助... :)

【讨论】:

嗯,有趣的机制 - 我可以看到它在某些情况下会有什么用处。不是 100% 肯定这会为我解决这个问题,因为通过脚本管理器插入的任何 js 都被 UpdatePanel 忽略了——我什至无法收到警报('hello world');跑步!无论如何,当它被嵌入占位符时,它不会:(会试一试,总是很高兴被反驳:) 请记住,这里的插入实际上是由 javascript 完成的,这就是它如此动态的原因。让我知道它是否有效。 哦...记住对 RegisterClientScriptBlock 的调用应该在 updatepanel prerrender 事件中... :) 嗨 Lucas - 这是我的问题 - 自定义控件在 UpdatePanel 内部,自定义控件尝试注册注册块,但 UpdatePanel 无法识别它 - 因此没有运行任何 JavaScript。我无法将 javascript 拉出控件并将其添加到页面 - 这将消除将行为封装在控件中的优势。【参考方案5】:

我遇到了 Page.ClientScript.RegisterStartUpScript 的问题 - 我没有使用更新面板,但控件已被缓存。这意味着我必须将脚本插入到 Literal(或者可以使用 PlaceHolder)中,因此当从缓存中渲染时,脚本会被包含在内。

类似的解决方案可能对您有用。

【讨论】:

谢谢 - 我会调查字符串文字,可能是一个很好的解决方法。我使用的是不同的插入技术,因为我使用的是 System.Web.Ui.ScriptManager 之外的静态方法,而不是 Page.ClientScript 机制【参考方案6】:

不要将 GUID 用于键

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

如果你想这样做,调用Something Like this function

 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", "");
 

【讨论】:

【参考方案7】:

对我有用的是在页面上注册它,同时将类型指定为 UpdatePanel 的类型,如下所示:

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

【讨论】:

【参考方案8】:

有时脚本有语法错误时它不会触发,请确保脚本和javascript语法正确。

【讨论】:

【参考方案9】:
ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(),script,  true );

ScriptManager.RegisterStartupScript 末尾的“true”参数值将在您的页面内添加一个 JavaScript 标记:

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

如果该值为“false”,它将只注入没有 --script-- 标签的脚本。

【讨论】:

【参考方案10】:

我尝试了很多东西,最后发现最后一个参数一定是假的,你必须在java脚本中添加&lt;SCRIPT&gt;标签:

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

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

【讨论】:

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

以上是关于无法让嵌套在 UpdatePanel 中的 WebControl 中的 ScriptManager.RegisterStartupScript 工作的主要内容,如果未能解决你的问题,请参考以下文章

UpdatePanel 中未更新的内容(在 Web 部件中)

UpdatePanel 启动脚本未执行

使用 UpdatePanel 从页面上的 Web 控件注册样式表

如何阻止 UpdatePanel 导致整个页面回发?

找不到ID为'xxx'的UpdatePanel。如果它是动态更新的,那么它必须在另一个UpdatePanel内

无法让嵌套类型保护与打字稿中的联合类型一起使用