How to Allow Generic Controls in ASP.NET Pages

Did you ever want to have a Repeater<Customer> control on your page? And its events were all strongly typed to recognize that each row was bound to a Customer object? Well, I came up with a way of doing it using some lesser known features of ASP.NET.

Today it's possible to use generic controls in ASP.NET, but you can't directly have a generic control in the tag markup. You'd typically have to do some trick such as deriving a concrete type from the generic type or instantiating the control from code-behind and adding it to a placeholder on the page.

My solution involves using a ControlBuilder to alter how the ASP.NET tag gets parsed. Typically ASP.NET parses a tag such as <cc:GenericControl runat="server" /> and instantiated a type called GenericControl in the mapped "cc" namespace. My ControlBuilder overrides that behavior by returning an instance of GenericControl<TDataItem> whenever that tag is encountered.

Here's an outline of my sample control:

namespace GenericControls {
    public class GenericControl<TDataItem> : Control where TDataItem : new() {
        public event EventHandler<GenericEventArgs<TDataItem>> Stuffing {
            add;
            remove;
        }
    }
}

Note that the control itself is generic over TDataItem, and that is exposes an event called "Stuffing" that uses a generic EventHandler with generic EventArgs also bound to TDataItem. So, if you have an instance of the GenericControl<Customer>, the event handler should take event arguments of type EventArgs<Customer>. Now you don't have to cast your event arguments to get to your data object!

To use the control you specify the generic argument in the form of a pseudo-property on the control tag itself called ObjectType:

        <gc:GenericControlGeneric runat="server" ID="CustomerGeneric"
            ObjectType="MyStuff.Customer, App_Code"
            OnStuffing="CustomerGeneric_Stuffing">
        </gc:GenericControlGeneric>

Yes, my naming convention is horrible. Unless you thing GenericControlGeneric sounds good. But it doesn't sound good; it's horrible! :)

And before anyone asks, the topic of generic syntax in tags has been discussed at length, so I won't repeat that here.

In summary, I encourage you to check it out and see if it helps solve any problems you've had, hopefully without creating any new problems. This was just a pet project I did to see whether it was possible to create generic controls in markup.

And finally, a caveat:

While this seems to work great at runtime, I've encountered some weird problems in Visual Studio to support this. For example, when you try to add an event handler for the Stuffing event through the property grid you might get some weird behavior.

Download the project source code here: GenericControl.zip

12 Comments

  • Nice.

    Now you only need to spend some time making copy of all of yours data-bound controls and make the new one support Generics ;)

    If you have plans of doing that the ObjectType could be set internally if we use a ObjectDataSource control, because the ObjectDataSource already specifies the type of the object to bind, wouldn't that be cool ;)

  • why do you have to use Generic Controls,
    when microsoft build them in ObjectDataSource.

  • See also:
    http://www.codeproject.com/KB/aspnet/TypedRepeater.aspx

  • Ivan Atansov:

    Most of the time when we need to add something to a control, like extending the GridView, we can use the DataBound event. By using the event args we can get the DataItem, to get the right interface we need to do a cast. This could be avoided by using a Generic GirdView control.

  • Very cool stuff, thanks for sharing!

  • Using a ControlBuilder make hard to create custom generic control. We have to implement a lot of specific class.

    I already encounter this problem, and I think about a custom build provider with a custom PageParseFilter. Thus no dummy specific control or specific ControlBuilder will be necessary.
    But it need a lot of work, and I opt for an easier solution.

    By the way, I prefer this approach :

  • My (I'm sure heavily flawed) approach has been

  • My approach has been something like this:
    [code]





    ...

    [/code]

    I'm sure there are a thousand reasons that is horrible to do, but it allowed me to encapsulate what I wanted to reuse (all of the html and javascript that is the same regardless of what kind of data it contains), and configure controls with xml files that our "powerusers" can make use of.

  • have you tried to get typed DataItem property for use in data binding expressions?

  • I wonder if there's a way to "automatically" declare the GenericControlGeneric of this page as a GenericControl in the page's designer file (default.aspx.designer.cs)?

    because in the code behind, i'd like to interact with the specific type (MyStuff.Customer) and not a simple object.

    Thanks
    Phil

  • yes for casting,
    and for performance your solution is best!

  • I didn't like the -.- proposal.

    Using a dash for this purpose struck me as counter-intuitive. SomeGenericControl-SomeObjectType looks like all one word.

    I'd propose using a double-colon to start the declaration and colons thereafter.

Comments have been disabled for this content.