More than just the basics with ASP.NET user controls

I was messing around with user controls, and this is like the 3rd time I’ve needed to look this up, so I figured I’d blog about it so I have it written down.

 

As you know, if you have some controls on an ASP.NET page, you could scoop those out and put those into a “User Control” – then drag that user control (the .ascx file) onto your .aspx page and voila. It’s a great way to isolate functionality and code.

 

Now, what if you need to pass the user control some data? Well, in the class of the user control, you can create public properties. For example:

 

private Unit _width = new Unit(400);

 

public Unit Width

{

    get

    {

        return _width;

    }

    set

    {

        _width = value;

    }

}

 

Then, when you create the control on your page, you’ll see that property available, like this:

 

<uc1:SectionHeader ID="sh1" runat="server" Width="400px">

</uc1:SectionHeader>

 

Now, what if you need to pass in something more? Perhaps you want to pass in a chunk of data. Or what if that chunk of data needs to be something even more complex, like ASP.NET controls? Well, there is this kind of obscure, poorly documented concept you can steal from the “templated controls” concept within web controls. You can have a user control, but also have “templates” that you can populate at runtime – with ANYthing that is valid within ASP.NET.

 

Let’s say you have this as your user control:

 

<div class="SectionHeader">

    <asp:PlaceHolder ID="Title" runat="server"></asp:PlaceHolder><br />

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

</div>

And let’s say we want to fill in Title and Description at runtime, by the caller – and I might want to put a bunch of things into that Description. Like, a calendar control, a gridview, just regular text - anything. What we need to do is create public ITemplate properties like this, in the user control class:

 

private ITemplate _title;

private ITemplate _description;

 

[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]

public ITemplate TitleTemplate

{

    get { return _title; }

    set { _title = value; }

}

[PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(TemplateControl))]

public ITemplate DescriptionTemplate

{

    get { return _description; }

    set { _description = value; }

}

 

Now, we just need to add some code to the OnInit, so that it will take the controls and/or text that a user entered for the Title and Description templates – and it puts them into the respective PlaceHolders on the user control page:

 

protected override void OnInit(EventArgs e)

{

    base.OnInit(e);

    if (_title != null)

    {

        _title.InstantiateIn(Title);

    }

    if (_description != null)

    {

        _description.InstantiateIn(Description);

    }

}

 

Note that the Title and Description up there, are the references to the placeholders on the page. So this is where it assigns what the user passed in – to the placeholders on your user control.

 

Lastly, add the attribute ParseChildren to the UserControl class, like this:

 

[ParseChildren(true)]

public partial class SectionHeader : System.Web.UI.UserControl

{

 

This tells intellisense on the caller page, to look for child objects (which TitleTemplate and DescriptionTemplate will be “templates” that you put in between the opening and closing tag of the control). So ParseChildren will just make sure it acts correctly when you create the control on the page.

 

When you do all this, this is what this will look like (and Intellisense supports this too) on the consuming side:

 

<uc1:SectionHeader ID="sh1" runat="server" Width="400px">

    <TitleTemplate>This is the title</TitleTemplate>

    <DescriptionTemplate>

        This is the description, and this has have controls in them

        too. For example:

<asp:Calendar ID="cal1" runat="server">

</asp:Calendar>

    </DescriptionTemplate>

</uc1:SectionHeader>

 

So this is quite a powerful and easy way to encapsulate and segregate UI functionality. Plus, it’s like a zillion times easier than manually rendering your own WebControl which is compiled in a .dll – which is nice, but there is no user interface, and you have to do all of your control creation programmatically. You have to figure that you are usually writing a custom control because you need to do something complicated - so that's the last place you want to be stuck without an interface!

posted on Sunday, June 04, 2006 9:47 AM by RobertSeder

Comments

# Adding Templates within UserControl

Sunday, June 04, 2006 12:08 PM by Bilal Haidar [MVP] :: Blog

# Adding Templates to ASP.NET 2.0 User Controls

Sunday, June 04, 2006 12:14 PM by Brad Wilson - The .NET Guy

# Creating

Monday, June 05, 2006 8:07 AM by Chris' Comments

# re: More than just the basics with ASP.NET user controls

Monday, June 05, 2006 10:56 AM by GLenn Johnson
This works in ASP.NET 1.1 but have you tried this in ASP.NET 2.0?
I can't get it to work because the inner template tag causes the following error:

Cannot switch views: Content is not allowed between the opening and closing tags for element 'ShipperControl'

ShipperControl is my user control that has a template.

# A notable entry on Templates

Monday, June 05, 2006 1:03 PM by IBenRush::MyBlog

# A notable entry on Templates

Monday, June 05, 2006 1:04 PM by IBenRush::MyBlog