Skip to main content

Containing Child Controls inside a UserControl

User Controls are a very quick and effective method to develop reusable controls for your application. They are usually much easier to develop than writing your own custom server controls.

I ran into a situation the other day that a user control we’ve made and had been working on for some time, just got a new requirement to be able to contain child server controls. I was a bit surprised to discover this is not a trivial matter.

It seems there is a weird limitation on User controls. If you try to put child controls in them or nest a user control inside another, the designer will complain. Furthermore if you thought you could use the PersistChildrenAttribute in order to convince the designer that your control is really intended to support this behavior, then think again – it seems that the designer simply ignores this possibility when it comes to user controls.

While searching for a solution, I discovered this post by Bobby DeRosa that suggested a reasonable solution. The problem with this solution is that you get XHTML validation errors. However, a comment in the post suggests a better solution.

While a Container User Control is not directly supported, a templated user control is supported by Microsoft.

And so, the below suggested solution will work nicely. Just to make things more interesting I made the sample control support two areas that can contain child controls; a header section and a content section.

The User Control’s code behind looks like this:

public partial class ContainerUserControl : UserControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
publicITemplate Header { get; set; }

[PersistenceMode(PersistenceMode.InnerProperty)]
publicITemplate Content { get; set; }

protected override voidOnInit(EventArgs e)
{
base.OnInit(e);
Content.InstantiateIn(ContentPlaceHolder);
Header.InstantiateIn(HeaderPlaceHolder);
}
}

While the markup should have a place holder for each section that will contain child elements:


  

<%@ControlLanguage="C#"AutoEventWireup="true"CodeBehind="ContainerUserControl.ascx.cs"Inherits="TestWebApp.ContainerUserControl"%>
<div>
<
asp:PlaceHolder ID="HeaderPlaceHolder"runat="server">
</
asp:PlaceHolder>

<
asp:PlaceHolder ID="ContentPlaceHolder"runat="server">
</
asp:PlaceHolder>
</
div>

And here is a sample of the usage:

 

<form id="form1" runat="server">
<
div>
<
uc:ContainerUserControl runat="server" ID="OuterContainer">
<
Header>
<
asp:Label ID="Label1" Text="Main label" runat="server" />
</
Header>
<
Content>
<
asp:Button ID="btnTest" runat="server" Text="Test me" />
</
Content>
</
uc:ContainerUserControl>
</
div>
</
form>

You can even nest a user control inside another user control:

<uc:ContainerUserControl runat="server" ID="OuterContainer">
<
Header>
<
asp:Label ID="Label1" Text="Main label" runat="server" />
</
Header>
<
Content>
<
uc:ContainerUserControl ID="InnerContainer" runat="server">
<
Header>
<
asp:Label runat="server" Text="Nested label"/>
</
Header>
<
Content>
<
h2>This is a nested content</h2>
</
Content>
</
uc:ContainerUserControl>
<
asp:Button ID="btnTest" runat="server" Text="Test me" />
</
Content>
</
uc:ContainerUserControl>

One more point to remember is that because the designer does not really support the inner content of the user control, you will not be able to refer directly to controls such as the above button. The reason is that the generated aspx.designer.cs will not include the inner controls as they are a part of the template. Therefore you will need code such as this to refer to the button:

this.OuterContainer.FindControl("btnTest");

Hopefully this will save you some time developing a full blown server control.

Comments

Popular posts from this blog

SSL must not be enabled for pickup-directory delivery methods

Maybe I'm just getting soft and lazy. It seems I've gotten used to just finding the answer to everything I need by googling it and relying on the community to solve it for me. I mean, at least when I’m not dealing with the bleeding edge of technology, I should expect to find a post from somebody who’s already ran into a similar problem – right? Well, I was a bit surprised when I tried to implement a simple email client using the totally mundane System.Net.Mail (really not bleeding edge, is it?), and received the following exception: “ SSL must not be enabled for pickup-directory delivery methods “ Happily I searched the web for this error message only to find two (2!) whole articles about it, none of which was any help at all. So, I figured it’s a good enough reason for my first blog post. After all, the blog itself has been ready and waiting for several months now for me to find the time and motivation to write something. But, I was doing something really trivial - ther...

Configuring your HTC HD2 Leo email account to use Wi-Fi

If you've read any of my posts, you probably know I'm not one to shy of Microsoft's technology. So, when it came to buying a smart phone I went for the best Hardware available - even if it means using Window Mobile as my my OS. Getting the best HW these days means the HTC HD2 Leo So, from time to time I'll post some tips here. If you want your email account to use Wi-Fi in order to send/receive your mail (instead of the expensive GPRS default) - do this: Start >> E-mail >> [select your account] >> Menu Options >> [select your account from the list (yea I know you did that in the previous step)] >> Edit Account Setup >>Next >> Next >> Next >> Next >> Advanced Server Settings >> In Network Connection select "The Internet" >> Done >> Next >> Next >> Finish That's a well hidden configuration wouldn't you say?