ScriptManager向页面添加多个脚本(重复)

4

这与五月份的这个未解决的问题完全相同。

(编辑)注意:这个未解决的帖子完全描述了这种行为——在用户控件中,通过ScriptManager.RegisterClientScriptBlock在UpdatePanel中添加额外脚本会导致重复。C# .NET 4.0。页面结构如下:

MasterPage
   Page
      UserControl1 (ascx) - loaded in code by Page
         UpdatePanel
            UserControl2 (ascx) - loaded in code by UserControl1

第一次将脚本添加到正文中是如预期的。代码只需在UserControl2 OnInit中简单地执行:
ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), "myscript", script, true);

我还尝试过使用“this”而不是页面来引用,但这并没有什么意义,因为如果用户控件在页面上加载多次,我不希望相同的脚本键重复出现在页面上,但无论如何都没有起作用。
在部分回发后,脚本会再次添加 - 但奇怪的是在页面的中,而不是body中,并且有趣的是,缺少asp.net通常添加的正常的//<![CDATA[...//]]>包装器。
另一个由UserControl1添加的脚本在部分回发后以完全相同的方式被复制。
有人知道为什么会发生这种情况吗?

你希望如何注册你的脚本?仅在整个页面生成时注册吗? - akonsu
@Chris 抱歉,你是对的,问题确实已经有答案了,但这不是我的问题,也许是他的问题,尽管它没有被接受。我正在使用相同的类型和密钥。我在其他地方找到了其他人提出这个问题,但没有解释或答案。 - Jamie Treworgy
@akonsu:脚本应该只在页面第一次生成时注册。但由于它位于UpdatePanel内部,代码会在每次部分回发时运行。我不能仅仅检查“IsPostback”,因为用户控件可以在回发时最初加载,因为它是表单中的其他控件的一部分,第一次加载时很可能会在回发上加载。 - Jamie Treworgy
你尝试过ScriptManager.RegisterStartupScript吗? - akonsu
如果你使用 typeof(UserControl2),会发生什么? - akonsu
显示剩余2条评论
3个回答

3

虽然我找不到关于ScriptManager是否无状态的讨论,但似乎ScriptManager是无状态的。因此,在部分异步回发过程中添加具有相同标记的脚本将导致重复。在实践中(对我而言),这种行为往往是不期望的,因为人们会认为在具有相同标记的UserControl内注册超过一次的任何脚本都是重复的,不应该再次注册。如果您真的想要注册一个新脚本(例如,在部分回发后发生了什么),我认为您应该需要为ScriptManager提供一个新标签来重新注册它。

我的解决方案是创建一个自定义的ScriptManager用于UserControl,并拥有一些方法,只在控件首次加载时注册脚本并使用ViewState维护状态信息。也就是说,我保留了一个用于存储仅打算在第一次注册的脚本的标记列表,并跨回发持久化它,只会重新注册未在该列表中找到的脚本。仅需注册一次的支持UserControl的脚本可以通过这种方式进行跟踪。

我不能仅仅使用IsPostBack的原因是有时我使用Page.LoadControl动态加载UserControl。不能保证在整个页面首次加载时加载控件。也就是说,它可能在回发时首次加载。因此,如果我仅使用IsPostBack,则脚本可能永远不会注册。


3
您可以添加一个检查来确认脚本是否已经被注册,然后再进行注册。
if (!Page.ClientScript.IsClientScriptRegistered (Page.GetType(), "myscript"))
   ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), "myscript", script, true);

我希望这可以帮助您。

ScriptManager 的整个意义不就是自动完成这一点吗?如果我使用 Page.GetType() 进行注册,那么 Me(我猜你指的是“this”)将无法与初始注册匹配。我会尝试一下,但似乎没有道理。 - Jamie Treworgy
没有问题。检查注册状态显示它尚未注册。实际上,在任何给定的页面加载中,我都没有多次调用该函数,因此这是有道理的,某种方式保留了先前部分回发的注册信息。 - Jamie Treworgy

2

您是否尝试在页面的Init/Load/PreRender/Render函数中使用简单的IsPostBack子句包装您的代码?这将防止在第一次页面加载后注册脚本。

if(!IsPostBack)
{
    ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), "myscript", script, true);
}

1
我无法做到这一点,因为在页面回发后第一次可能会动态加载一个用户控件。 - Jamie Treworgy
虽然我似乎找不到任何关于这个的正面文档,但我相信这实际上是ScriptManager的设计 - 它不维护状态,因此“标记”只会防止给定页面加载中的重复。解决方案是使用维护状态的方法扩展它,但基本上你是正确的。 - Jamie Treworgy
如果使用 @Scripts.Render("MyASPNETMVC5Bundle"),这个是如何工作的? - daniel.caspers

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