views:

3241

answers:

3

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

A: 

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.

Chris Mullins
A: 

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.

InfinitiesLoop
A: 

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...

Mad Halfling
Sounds like you know what you're doing though! Please let me know if you find a solution!
Darrell
one caveat with my above edit, adding the controls programmatically potentially adds in a level of complexity regarding viewstate, etc. so my boj-job of just adding an SCM to the parent (maybe put a comment in the control mentioning this) may be a "better" option unless you require that level or self-dependence/portability.
Mad Halfling