Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render multiple control collections in ASP.NET custom control

I've build a custom WebControl, which has the following structure:

<gws:ModalBox ID="ModalBox1" HeaderText="Title" runat="server">
    <Contents>
        <asp:Label ID="KeywordLabel" AssociatedControlID="KeywordTextBox" runat="server">Keyword: </asp:Label><br />
        <asp:TextBox ID="KeywordTextBox" Text="" runat="server" />
    </Contents>
    <Footer>(controls...)</Footer>
</gws:ModalBox>

The control contains two ControlCollection properties, 'Contents' and 'Footer'. Never tried to build a control with multiple control collections, but solved it like this (simplified):

[PersistChildren(false), ParseChildren(true)]
public class ModalBox : WebControl
{
    private ControlCollection _contents;
    private ControlCollection _footer;

    public ModalBox()
        : base()
    {
        this._contents = base.CreateControlCollection();
        this._footer = base.CreateControlCollection();
    }

    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ControlCollection Contents { get { return this._contents; } }

    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ControlCollection Footer { get { return this._footer; } }

    protected override void RenderContents(HtmlTextWriter output)
    {
        // Render content controls.
        foreach (Control control in this.Contents)
        {
            control.RenderControl(output);
        }

        // Render footer controls.
        foreach (Control control in this.Footer)
        {
            control.RenderControl(output);
        }
    }
}

However it seems to render properly, it doesn't work anymore if I add some asp.net labels and input controls inside the property (see above asp.net code). I'll get the HttpException:

Unable to find control with id 'KeywordTextBox' that is associated with the Label 'KeywordLabel'.

Somewhat understandable, because the label appears before the textbox in the controlcollection. However, with default asp.net controls it does work, so why doesn't this work? What am I doing wrong? Is it even possible to have two control collections in one control? Should I render it differently?

Thanks for replies.

like image 682
Herman Cordes Avatar asked Mar 15 '10 13:03

Herman Cordes


2 Answers

You can use two Panels as parents of your two control collections (and they would provide grouping and improved readability). Add your controls from each collection to the Controls collection of respective panel, and in the Render method just call Render methods of each panel. Panels will automatically render their children, and will provide them with their own namespace, so, you can have controls with similar IDs in different panels.

like image 57
Kaerber Avatar answered Oct 19 '22 22:10

Kaerber


I'm not sure that will work. If you make use of templates however you can get the control to render output correctly.

First, define a class to be used as the type for the container control:

public class ContentsTemplate : Control, INamingContainer
{
}

And now the custom control:

[PersistChildren(false), ParseChildren(true)]
public class ModalBox : CompositeControl
{

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Contents { get; set; }

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Footer { get; set; }

  protected override void CreateChildControls()
  {
    Controls.Clear();

    var contentsItem = new ContentsTemplate();
    Contents.InstantiateIn(contentsItem);
    Controls.Add(contentsItem);

    var footerItem = new ContentsTemplate();
    Footer.InstantiateIn(footerItem);
    Controls.Add(footerItem);
  }

}
like image 41
David Gardiner Avatar answered Oct 19 '22 23:10

David Gardiner