Darrell
Darrell

Reputation: 355

UserControl with UpdatePanel programmatically create ScriptManager possible?

I'd like to use an UpdatePanel in my UserControl. The problem is the .aspx page the control is dropped on will NOT have a ScriptManager. I will need to create the ScriptManager in the UserControl. However if the UserControl is used, say twice on the page, then placing a ScriptManager won't work because you can only initialize ScriptManager once.

In other UserControls where I needed ScriptManager (I was using AJAX Toolkit Extensions) I was able to use this code:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    Page.Init += new EventHandler(Page_Init);
}

void Page_Init(object sender, EventArgs e)
{
    if (Page.Form != null && ScriptManager.GetCurrent(Page) == null)
        Page.Form.Controls.AddAt(0, new ScriptManager());
}

..worked great, but not for the UpdatePanel case.

Note, I am NOT using Master Pages

(Another approach I was thinking of, but can't figure out how to do, is to programmatically create the UserControl inside an UpdatePanel.)

Upvotes: 1

Views: 11547

Answers (5)

kad81
kad81

Reputation: 10950

Instead of dynamically adding a ScriptManager if none exists on the page, simply do the opposite: add a ScriptManager to your ASCX and get rid of it if there's one already on the page. So...

protected override void OnInit(EventArgs e) {
    base.OnInit(e);
    AdjustScriptManager();
}

private void AdjustScriptManager() {
    if (ScriptManager.GetCurrent(Page) != null) {
        ScriptManager1 = null;
    }
}

UPDATE:

Nah, after further testing this won't work, as ScriptManager1 = null does nothing helpful. If there is a way to do this (or to remove the Page control), please comment.

Upvotes: 0

Spyder
Spyder

Reputation: 4032

Solution: you can add a scriptmanager dynamically in the usercontrol by checking if the current page does not already contain a ScriptManager. Here's how:)

In the UserControl (ascx) html put this:

<asp:PlaceHolder ID="pHolder" runat="server" />

And in the code behind (ascx.cs):

    //insert Scriptmanager dynamically only IF it does not already exist
     private void createScriptManager(System.EventArgs e)
    {
        // the GetCurrent() method will return a ScriptManager from the Page
        if (System.Web.UI.AjaxScriptManager.GetCurrent(this.Page) == null)
        {
            System.Web.UI.AjaxScriptManager manager = new System.Web.UI.AjaxScriptManager();
            manager.EnablePartialRendering = true;
            pHolder.Controls.Add(manager);
        }
    }

    // call the above method from the usercontrol's OnInit
    override protected void OnInit(EventArgs e)
    {
        //
        // CODEGEN: This call is required by the ASP.NET Web Form Designer.
        //
        createScriptManager(e);
        base.OnInit(e);
    }

Sometimes it is necessary to define a ScriptManager dynamically. In my case I am using a usercontrol that will be put into different pages, but some of these pages already contain a ScriptManager and some dont, so how will my usercontrol know if it should define its own ScriptManager? The beauty of the above code is that the usercontrol adds a scriptmanager only if there isn't already one on the page.

Note: the System.Web.UI.AjaxScriptManager may be replaced with System.Web.UI.ScriptManager if you use an older version of Ajax.

Upvotes: -1

Mad Halfling
Mad Halfling

Reputation: 968

I am hitting this same problem. The problem is that you need to add the scriptmanager before the OnInit stage - as far as I can see it needs to be done at the preinit stage. You can see this by adding a load of overrides - I found the the page got through the preinit ok, then went to the addedcontrol event and it was at (or just after, but this point makes sense) that the "You need a scriptmanager" gets thrown. I am struggling to find how to add an event handler to the Page.PreInit event from a child usercontrol as the WUCs don't have a PreInit event. Even the WUC constructor doesn't fire before that point and in the constructor the page object is null so you can't add it there. Even at the AddedControl stage of the WUC, you still don't seem to be able to access the main page ( ScriptManager oSCM = ScriptManager.GetCurrent(Page); returns null) so you can't seem to add the scriptmanager, if you need to, before the error is thrown.

/edit:- As far as I can see it (and I've had no answer to this on the asp.net forums - surprise, surprise) the WUC doesn't start kicking in it's methods/events until after the parent's preinit stage, so there's 2 ways of doing this.

1) The way I think I would do this is to not put any content in the designer that requires the scriptmanager and to put placeholders where such content needs to go. Then in the wuc load you use the ScriptManager.GetCurrent to see if there's one already there and then create it if not. Then you dynamically add the content that requires the SCM. Something like this:-


<%@ Control Language="C#" AutoEventWireup="true" CodeFile="wucTestExample.ascx.cs" Inherits="wucTestExample" %>

<asp:PlaceHolder ID="plcAJAX" runat="server" />
<asp:Label ID="lblGeneral" runat="server" Text="This is another label" />

----------------code behind---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class wucTestExample : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ScriptManager oSCM = ScriptManager.GetCurrent(this.Page);
        if (oSCM == null)
        {
            oSCM = new ScriptManager();
            oSCM.ID = "scmAJAX";
            oSCM.EnablePartialRendering = true;
            this.plcAJAX.Controls.AddAt(0, oSCM);
        }

        UpdatePanel udpMain = new UpdatePanel();
        udpMain.ID = "udpMain";

        TextBox txtMain = new TextBox();
        txtMain.ID = "txtMain";
        // other attrbutes here

        Button btnPostback = new Button();
        btnPostback.ID = "btnPostback";
        btnPostback.Click += new EventHandler(btnPostback_Click);
        btnPostback.Text = "Partial Postback";

        Label lblPostback = new Label();
        lblPostback.ID = "lblPostback";
        lblPostback.Text = "initial postback";

        udpMain.ContentTemplateContainer.Controls.Add(txtMain);
        udpMain.ContentTemplateContainer.Controls.Add(btnPostback);
        udpMain.ContentTemplateContainer.Controls.Add(lblPostback);

        this.plcAJAX.Controls.Add(udpMain);
    }

    void btnPostback_Click(object sender, EventArgs e)
    {
        // implement button code here
        Label lblPostback = (Label)this.plcAJAX.FindControl("lblPostback");
        if (lblPostback != null)
        {
            lblPostback.Text = String.Format("WUC POstback at : {0}", DateTime.Now.ToLongTimeString());
        }
    }
}

then use it thus:-


<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="TestExampleNoSCM.aspx.cs" Inherits="TestExampleNoSCM" %>
<%@ Register Src="~/wucTestExample.ascx" TagName="wucTestExample" TagPrefix="ucTE" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <%--<asp:ScriptManager ID="scmAJAX" runat="server" />--%>
    <asp:Label ID="lblLoadTime" runat="server" />
    <ucTE:wucTestExample ID="wucTestExample" runat="server" />
</asp:Content>

----------------code behind---------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class TestExampleNoSCM : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.lblLoadTime.Text = String.Format("Page load at: {0}",DateTime.Now.ToLongTimeString());
    }
}

So if you comment or uncomment the SCM in the parent page, the WUC still works either way.

2) I've seen another option where an update panel was needed and the programmer created all the controls in the designer and then looped round them in the page load (after creating the SCM, if needed, and the UDP and added all the controls on the WUC UDP, before then adding that to to placeholder, but this strikes me as rather dangerous as it seems to be double-instantiating control, and I think it may come back to bite them on the bum...

The downside with method 1 is that it's more work to create everything in your updatepanel programmatically, but if you really want to build a self-dependent WUC, that seems to be your price (and hopefully, the WUC shouldn't be that complicated, anyway). Personally, I think in my app (as the WUC won't be used outside it) I'll just make sure I add in an SCM where needed on the main page.

One other, final, note I would pitch in - I've seen people saying "add it to the master page" - this seems to be a particularly bad idea, IMHO, unless every page in your app needs the SCM as it will add a whole new level of bloat to your pages, and that doesn't seem to be a good idea as ASP.NET seems to have a good level of bloat already...

Upvotes: 0

InfinitiesLoop
InfinitiesLoop

Reputation: 14599

What is the reason it doesn't work? Are you getting an exception from the UpdatePanel that a ScriptManager is required? Are you using System.Web.Extensions 1.0 or 3.5? I say that because a change was made to UpdatePanel in 3.5 that causes its content template to instantiate prior to OnInit, so I don't see an obvious reason why that wouldn't work. If there is an exception it would be helpful to see the stack trace.

Upvotes: 0

Chris Mullins
Chris Mullins

Reputation: 6867

I do not think this is possible. I have tried it several different ways. You might have to bite the bullet and put a scriptmanager in your page.

Upvotes: 0

Related Questions