On the OnPreRender of my custom server control, I am registering an alert to popup everytime the page is loaded after a partial postback (add_pageLoaded(function() { alert('Hi')})). I only want this to be called once, but its gets called as many times as there has been partial postbacks. For example, in the code below, if you open the page and click "Click me" you get one alert, click again and you will get two alerts, three --> three alerts and so forth. My understanding was that ScriptManager.RegisterClientScriptBlock, using the scriptKey parameter was suppose to check if the script has already been registered, and if so, dont register it again. I cannot register this script on !IsPostBack because my custom control will be inserted during Postbacks into pages, so using !IsPostBack will not include my script.
Here is a simple example of this problem:
ASPX:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="RegisterClientScriptExperimentation._Default" %>
<%@ Register Assembly="RegisterClientScriptExperimentation" Namespace="RegisterClientScriptExperimentation" TagPrefix="cc" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server"/>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Panel ID="panel" runat="server"/>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
namespace RegisterClientScriptExperimentation
{
public partial class _Default : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
panel.Controls.Add(new CustomControl());
}
}
public class CustomControl : CompositeControl
{
private Button button;
public CustomControl()
{
button = new Button();
button.Text = "Click me";
}
protected override void CreateChildControls()
{
Controls.Clear();
Controls.Add(button);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
StringBuilder _text = new StringBuilder();
_text.Append("var prm = Sys.WebForms.PageRequestManager.getInstance();");
_text.Append("prm.add_pageLoaded(function() { alert('Page Loaded'); });");
if (null != System.Web.UI.ScriptManager.GetCurrent(Page) && System.Web.UI.ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
System.Web.UI.ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "customControlScript", _text.ToString(), true);
else
Page.ClientScript.RegisterStartupScript(this.GetType(), "customControlScript", _text.ToString(), true);
}
}
}
I found the solution to this.
In your page events, after you execute whatever you need to do, you need to remove the function from the event which you hooked into.
For example:
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_pageLoaded(DoSomething);
function DoSomething() {
alert('Hello');
Sys.WebForms.PageRequestManager.getInstance().remove_pageLoaded(DoSomething);
}