Wednesday, March 21, 2012

Is it possible to add a ScriptManager to a page dynamically?

As per the title, is it possible to add a script manager to a page from code?

I have it working OK if the UpdatePanel is also created in code (explicitly after the script manager is created) but not if the UpdatePanel is defined in the aspx template. In that case, if I put my code in "OnInit", the page raises an exception saying that "the Script manager needs to be added (to the page's control tree) before the UpdatePanel", whereas if I move the code to "OnPreInit" then the controls collection is not even created yet.

In other words, adding the Script Manager "OnPreInit" is too early but adding it "OnInit" is too late IF the UpdatePanel is defined in the aspx.

The reason I'm asking is that it would be nice to be able to write controls that could detect if the Page they are hosted in has a Script Manager (or proxy?) and if not, and if they need to use AJAX, then the control can add one, theus removing this dependancy and "knowledge of the implementation" from the client using the control.

Any ideas?

Many thanks

I use a simple workaround-- add a property that says UseAJAX (boolean), and in the XML documentation for the control I say that if the control is on a page with a ScriptManager, or in an UpdatePanel, to set this value to true.

Then the control takes this into account when instantiating and building the control structure, as well as when registering scripts.


OK thanks, that would be OK - obviously this is something you've already come across and worked around.

I did have some ideas on these lines myself, like having an IAjaxControl interface that had a method like "EnableAjax()" that would create & append the UpdatePanels to the control - one of the reasons being that the UpdatePanels, once created and added to the control tree CANNOT be moved so if the client wants to take the control and move it to another part of the tree then it will cause an exception. Having the method, rather than a property, gives the client some control as to WHEN to trigger the creation of the Ajax components (ideally after the control tree is "set in stone").

With hindsight, I think I like your idea of a simple boolean property (but defined in the IAjaxControl interface) and always create the UpdatePanels in the OnLoad (if the boolean is true) rather than beforehand - hopefully then the control tree is final and we are safe to do it, and the GUI designer can support the boolean property withought the need for coding from the client.

I felt the interface was needed for scenarios like where a different control CONTAINED your Ajax enabled control - it too would then need to support the property (and pass it down to your control it was containing).


Did you find a solution (Like you, I try the OnInit and the PreOnInit) ?

All my pages inherits the same class (let's say PageAncestry). I want to add the scriptmanager with code in PageAncestry so all my pages will automatically be able to use ajax.


After some google search, I finally found a solution on this page http://www.capdes.com/2007/02/microsoft_office_sharepoint_se.html

Add the ScriptManager in the PreInit at the HtmlForm first position :

Private Sub Page_PreInit(ByVal poSender As Object, ByVal poArguments As System.EventArgs) Handles Me.PreInit

' Get current ScriptManager if exist
Dim oScriptManagerAjax As ScriptManager = ScriptManager.GetCurrent(Me)
' If not exist
If oScriptManagerAjax Is Nothing Then
' Create one
oScriptManagerAjax = New ScriptManager
' Get page form
Dim oForm As HtmlForm = Me.Form
' If form present
If Not IsNothing(oForm) Then
' Add it at first position
oForm.Controls.AddAt(0, oScriptManagerAjax)
Else
' Manage if not (impossible to use Ajax)
End If
End If


End Sub


Hmm, from what I was saying:

"whereas if I move the code to "OnPreInit" then the controls collection is not even created yet."

and yet, in "PreInit" you have code:

oForm.Controls.AddAt(0, oScriptManagerAjax)

Are you sure thius works? According to my original post "oForm.Controls.Add" should have raised an exception as the "Controls" collection is not yet created. Are you sure your code works?

My page also uses a MasterPage - does yours? Does that make a difference (i wonder??)

I'll give it a try tomorrow. Thanks for the post :)


Yes it's working for me.

I don't have a master page, so I don't know if it's working with.

The most important thing is theControls.addat(0, it put the ScriptManager before all other controls define in the form (even the one in design). It's not working if you use only Controls.add


I'm pretty sure that "Controls.AddAt(0..." is what I was using before - as I said though, I believe the "Controls" collection was null at PreInit.

Anyway, I will try again and post my results :)


No mate, this just doesn't work, not in C# anyway.

The isssue is as before but I was mistaken, it's not the Control collection that is not created, it is the Form object itself.

Here is my ASPX Template:

<%@. Page Language="C#" AutoEventWireup="true" CodeFile="Page2.aspx.cs" Inherits="Page2" %><!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>Untitled Page</title></head><body> <form id="form1" runat="server"> <div> Page 2<br /> <br /> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label><br /> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </ContentTemplate> </asp:UpdatePanel> </div> </form></body></html>

And here is my code behind:

using System;using System.Data;using System.Configuration;using System.Collections;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 partialclass Page2 : Page{protected override void OnPreInit(EventArgs e) {// Pop a script manager on the page if one does not yet exist. ScriptManager scriptManager = ScriptManager.GetCurrent(this);if (scriptManager ==null) { scriptManager =new ScriptManager(); HtmlForm form =this.Form;if (form !=null) form.Controls.AddAt(0, scriptManager); }base.OnPreInit(e); }protected void Button1_Click(object sender, EventArgs e) { Label1.Text = DateTime.Now.ToLongTimeString(); }}

As you see here, if "form" is null we can't add the script manager, and this.Form IS null at "PreInit":

if

(form !=null)
form.Controls.AddAt(0, scriptManager);

The only way I could get this to work is doing it in the "Onint" where the ScriptManager is created first and then the UpdatePanel created IN CODE afterwards (NOT defined in the aspx). Unfortunately, defining the Update Panel in the aspx means that "Oninit" is too late to add the script manager, but "PreInit" is too early as the form is not yet created.

Please tell me I'm wrong about this - how have you got this to work? I don't get it. Can you post your ASPX & VB code?



Not works!!!

Obviously the code is in the OnInit andnot in OnPreInit at http://www.capdes.com/2007/02/microsoft_office_sharepoint_se.htmlSmile

I think the msdn documentation not correct about the preinit event, this is an excerpt of my offline msdn library (seeit online):

PreInit

Use this event for the following:

Check theIsPostBack property to determine whether this is the first time the page is being processed.


Yes stmarti, although I think the documentation is (technically) correct in that you can CREATE controls at OnPreInit but you CANNOT add them to your Form, as it does not yet exist!

If you do this in OnPreInit:

Label label =newLabel();
label.Text ="Hello PreInit world";
this.Controls.Add(label);

and you'll see that the label ends up rendering AFTER ALL HTML MARKUP!!!! (ie was added to the control tree FIRST, then the Form was Added AT(0) with all real content then added to the form - leaving your poor Label "out in the cold".

So if the Form is not yet created at OnPreInit, I can't see how the VB code posted above could work.


Just tested this:

Private Sub Page_PreInit(ByVal poSender As Object, ByVal poArguments As System.EventArgs) Handles Me.PreInit

' Get current ScriptManager if exist
Dim oScriptManagerAjax As ScriptManager = ScriptManager.GetCurrent(Me)
' If not exist
If oScriptManagerAjax Is Nothing Then
' Create one
oScriptManagerAjax = New ScriptManager
' Get page form
Dim oForm As HtmlForm = Me.Form
' If form present
If Not IsNothing(oForm) Then
' Add it at first position
oForm.Controls.AddAt(0, oScriptManagerAjax)
Else
' Manage if not (impossible to use Ajax)
End If
End If

End Sub

And it works.... only when you havealreadya scriptmanager in the aspx. Obviously this code in real do nothing special because:

- if you have already a scriptmanager on the page the code does nothing, and your page is just fine...

- if you have not a scriptmanager in the aspx, the following code

' Add it at first position
oForm.Controls.AddAt(0, oScriptManagerAjax)

neverwill be executed because oForm is null in preinitSmile! Anyway your page will throw exception and cry for a scriptmanager...


VR2:

Yes stmarti, although I think the documentation is (technically) correct in that you can CREATE controls at OnPreInit but you CANNOT add them to your Form, as it does not yet exist!

You are right. Technically it's correct. The doc (at least this entry in msdn) suggest preinit for creating dynamic controls, and init for setting control properties. This is not true for the form's controls, would be nice a remark about it in the future.


I try your C# code and it's not working :(

But I found the difference with my vb code :) (I can't post it, it's included in a bigger class)

I use FindControl to search the Form !

Just change the OnPreInit in your code by this one and it's workingBig Smile
protected override void OnPreInit(EventArgs e) { ScriptManager scriptManager = ScriptManager.GetCurrent(this);if (scriptManager ==null) { scriptManager =new ScriptManager(); Control oControl =this.FindControl("Form1");if (oControl !=null) { oControl.Controls.AddAt(0, scriptManager); } }base.OnPreInit(e); }

It works!!! Like thisBig Smile:

protected override void OnPreInit( EventArgs e )
{
HtmlForm form1 = ( HtmlForm )this.FindControl( "Form1" );

ScriptManager temp = new ScriptManager( );
temp.EnablePageMethods = true;

form1.Controls.AddAt( 0, temp );

base.OnPreInit( e );
}

Great work gbarry! The problem solved and the answere for:

Is it possible to add a ScriptManager to a page dynamically?

is:yes! Yes

No comments:

Post a Comment