Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to page control collection from inside a user control

I have an asp.net usercontrol which represents a "popup" dialog. Basically, it's a wrapper for the jQuery UI dialog which can be subclassed to easily make dialogs.

As part of this control, I need to inject a div into the page the control is used on, either at the very top or very bottom of the form so that when the popup is instantiated, it's parent is changed to this div. This allows "nested" popups without the child popup being trapped inside the parent popup.

The trouble is, I can't find a safe way to inject this div into the page. A usercontrol doesn't have a preinit event, so I can't do it there, and calling Page.Form.Controls.Add(...) in Init, Load or PreRender causes the standard exception "The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases."

I thought I had found a solution by using...

ScriptManager.RegisterClientScriptBlock(Page, Me.GetType, UniqueID + "_Dialog_Div", containerDiv, False)

... which seemed to work well normally, but recently a coworker tried putting an UpdatePanel inside the dialog and now she's getting the error "The script tag registered for type 'ASP.controls_order_viewzips_ascx' and key 'ctl00$ContentBody$OViewZips_Dialog_Div' has invalid characters outside of the script tags: . Only properly formatted script tags can be registered."

How are you supposed to add controls to the pages control collection from inside a user control?

like image 408
Zarigani Avatar asked Feb 12 '11 01:02

Zarigani


2 Answers

I'm not sure why you really need to add this div to the page's form, but this should work:

  Public Class WebUserControl1
    Inherits System.Web.UI.UserControl

        Private Sub UC_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            AddHandler Me.Page.Init, AddressOf Me.Page_Init
        End Sub

        Private Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
            Dim dialogDiv As New Panel
            dialogDiv.ID = "DialogDiv"
            If Not Page.Form.Controls.Contains(dialogDiv) Then
                Page.Form.Controls.AddAt(0, dialogDiv)
            End If
        End Sub

    End Class

How to implement it in C#. I'm always getting the error The control collection cannot be modified on Load, PreRender I need a Literal Control to be added to my master page's head from a user control. The literal control will contain the css link.

Do you want to add the literal to the HeadContent-ContentPlaceHolder control in the master or to the page's header(the html head element)? However, here i show both.

Here's the codebehind of your UserControl:

public partial class UC_AddToMaster : System.Web.UI.UserControl
{
    private void Page_Init(object sender, System.EventArgs e)
    {
        this.Page.Init += UC_AddToMaster_Init;
    }

    private void UC_AddToMaster_Init(object sender, EventArgs e)
    {
        Literal literal = new Literal{ Text = "Hi World!" };
        // if you want to add it to the header of the page:
        if (!Page.Header.Controls.Contains(literal))
        {
            Page.Header.Controls.AddAt(0, literal);
        }

        // if you want to add it to the master's HeadContent ContentPlaceHolder control:
        var siteMaster = Page.Master as SiteMaster;
        if (siteMaster != null)
        {
            if (!siteMaster.Head.Controls.Contains(literal))
            {
                siteMaster.Head.Controls.AddAt(0, literal);
            }
        }
    }
}

For the HeadContent approach mentioned above i've provided following property in the master:

// in the master
public ContentPlaceHolder Head { get { return this.HeadContent; } }

Therefore i needed to cast the page's master to it's actual type(SiteMaster here) in the UserControl. Otherwise i couldn't access this property.

like image 80
Tim Schmelter Avatar answered Oct 01 '22 15:10

Tim Schmelter


Usercontrol doesn't have a PreInit event, but nothing's stopping you from adding a handler to the Page PreInit event in your UserControl:

Page.PreInit += new EventHandler(Page_PreInit);

edit - you're right - you can't capture PreInit from a usercontrol, though I'm surprised you can't - but you can still change the page controls collection by adding code to the constructor of the UserControl. I tried this and it works.

public MyUsercontrol()
{
    Page page = (Page)HttpContext.Current.Handler;
    Literal lit = new Literal();
    lit.Text="text";
    page.Controls.Add(lit);
}

Adding an event handler to Page.PreInit in the constructor compiles but it never fires.

(end edit)

That said, I'm not exactly sure why this is necessary to achieve your goal. Why don't you just have your dialog control render it's own div in-line wherever you drop it into the form, and use that as the parent, instead of trying to create one somewhere else in the form? I can't think of why it would be important for it to physically be rendered at the beginning or end of the form. It's a dialog so it will always be invisible until you use it, right?

like image 43
Jamie Treworgy Avatar answered Oct 01 '22 17:10

Jamie Treworgy