Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating Custom User Control Designers in ASP.NET

0.00/5 (No votes)
7 Apr 2005 1  
An article on creating custom User Control designers in ASP.NET.

User Control Designer in Action

Introduction

A User Control is a server control that can be authored using declarative style as an ASP.NET web page. They provide web developers a quick way to create server controls.

User controls suffer from minimal design-time support in VS.NET. Their properties cannot be edited using Property Grid. This article is an attempt to create Custom Designers for User Controls which allow to edit their properties using Property Grid.

Header User Control

The code below shows a Header User Control which exposes Heading and SubHeading properties to allow the user to provide a heading and subheading for the page.

VB.NET

<%@ Control Language="vb" AutoEventWireup="false" 
        Codebehind= "Header.ascx.vb" Inherits="CustomDesignersWebVB.Header" %> 
<table align="center" ID= "tblHeader">
<tr>
    <td><asp:label id="lblHeading" Font-Size="18" Font-Name="Arial" 
          Font-Bold="True" Runat="server">Heading</asp:label></td>
</tr>
<tr>
    <td><asp:label id="lblSubHeading" Font-Size="14" Font-Name="Arial" 
          Font-Bold="True" Runat="server">Sub Heading</asp:label></td>
</tr>
</table>
Public Property Heading() As String
    Get
        Return lblHeading.Text
    End Get
    Set(ByVal Value As String)
        lblHeading.Text = Value
    End Set
End Property

Public Property SubHeading() As String
    Get
        Return lblSubHeading.Text
    End Get
    Set(ByVal Value As String)
        lblSubHeading.Text = Value
    End Set
End Property

C#

<%@ Control Language="C#" AutoEventWireup="false" 
      Codebehind= "Header.ascx.cs" Inherits="CustomDesignersWebCS.Header" %>
<table align="center" ID= "tblHeader">
<tr>
    <td><asp:label id="lblHeading" Font-Size="18" Font-Name="Arial" 
         Font-Bold="True" Runat="server">Heading</asp:label></td>
</tr>
<tr>
    <td><asp:label id="lblSubHeading" Font-Size="14" Font-Name="Arial" 
         Font-Bold="True" Runat="server">Sub Heading</asp:label></td>
</tr>
</table>
public string Heading
{
    get
    {
        return lblHeading.Text;
    }
    set
    {
        lblHeading.Text=value;
    }
}

public string SubHeading
{
    get
    {
        return lblSubHeading.Text;
    }
    set
    {
        lblSubHeading.Text=value;
    }
}

Creating a Custom Designer for Header User Control

Fire up Visual Studio .NET, use the File | New | Project menu item and select Web Control Library project template.

Add a Component Class to the project as shown below:

Creating the New Component Class

A Component Class is a class that inherits System.Component.Component. It can be added to the toolbox of VS.NET and can be dragged and dropped onto the design surface, and when selected, its properties are displayed using Property Grid.

Following is the code listing for the HeaderDesigner component class:

C#

private string _Heading ;
private string _SubHeading;

public string Heading
{
    get
    {
        return _Heading;
    }
    set
    {
        _Heading=value;
    }
}

public string SubHeading
{
    get
    {
        return _SubHeading;
    }
    set
    {
        _SubHeading=value;
    }
}

VB.NET

Private _Heading As String
Private _SubHeading As String

Public Property Heading() As String
        Get
            Return _Heading
        End Get
        Set(ByVal Value As String)
            _Heading = Value
        End Set
End Property

Public Property SubHeading() As String
    Get
        Return _SubHeading
    End Get
    Set(ByVal Value As String)
        _SubHeading = Value
    End Set
End Property

Header Designer exposes Heading and SubHeading properties to the user. The user sets these properties using a Property Grid.

Associating Designer with Header User Control

Open the project containing Header User Control. Add the HeaderDesigner component to the Components tab in the Toolbox, as shown below:

Adding HeaderDesigner to Toolbox

Drag and drop the HeaderDesigner to the design surface. Now you can set the Heading and SubHeading properties using the Property Grid as shown:

Setting Properties for UserControl

Open the code-behind for the page and add the following code:

C#

protected  Header Header1;
private void Page_Load(object sender, System.EventArgs e)
{
    //Glue code to associate the Usercontrol with the Designer

    if(!IsPostBack)
    {
      CustomDesignersCS.DesignerHelper.BindDesignerToControl(headerDesigner1, 
                                                                    Header1);
    }
}

VB.NET

Protected Header1 As Header

Private Sub Page_Load(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles MyBase.Load
    If Not Page.IsPostBack Then
      CustomDesignersVB.DesignerHelper.BindDesignerToControl(HeaderDesigner1, _
                                                                        Header1)
    End If
End Sub

BindDesignerToControl function is the glue code which binds HeaderDesigner properties to the user control properties. It uses Reflection to read Designer properties and associate them with the corresponding properties in the Header User Control.

C#

public class DesignerHelper
{
    public static void 
      BindDesignerToControl(System.ComponentModel.Component designer, Control ctl)
    {
        BindDesignerToObject(designer, ctl);
    }

    public static void 
      BindDesignerToObject(System.ComponentModel.Component designer, Object obj)
    {
        //Get object properties using Reflection

        PropertyDescriptorCollection colWebCtlPropDesc = 
                      TypeDescriptor.GetProperties(obj);

        //Get Designer properties using Reflection

        PropertyDescriptorCollection coldesignerPropDesc = 
                   TypeDescriptor.GetProperties(designer);

        //Loop through all Designer properties

        //Each designer property corresponds to webcontrol property

        foreach(PropertyDescriptor pd in coldesignerPropDesc)
        {
                PropertyDescriptor webctlpd = colWebCtlPropDesc.Find(pd.Name, true);

            if (webctlpd!=null)
            {
                //Assign the designer property value to web control's property

                webctlpd.SetValue(obj, pd.GetValue(designer));
            }

        }
    }
}

VB.NET

Public NotInheritable Class DesignerHelper _
    Public Shared Sub BindDesignerToControl(ByVal designer As _
    System.ComponentModel.Component, ByRef ctl As Control)
        BindDesignerToObject(designer, ctl)
    End Sub

    Public Shared Sub BindDesignerToObject(ByVal designer As _
           System.ComponentModel.Component, ByRef obj As Object)

        'Get object properties using Reflection

        Dim colWebCtlPropDesc As PropertyDescriptorCollection = _
                                 TypeDescriptor.GetProperties(obj)

        'Get Designer properties using Reflection

        Dim coldesignerPropDesc As PropertyDescriptorCollection = _
                              TypeDescriptor.GetProperties(designer)

        'Loop through Designer properties

        'Each designer property corresponds to webcontrol property

        For Each pd As PropertyDescriptor In coldesignerPropDesc
            Dim webctlpd As PropertyDescriptor = _
                           colWebCtlPropDesc.Find(pd.Name, True)

            If Not IsNothing(webctlpd) Then
                'Assign the designer property value to web control

                webctlpd.SetValue(obj, pd.GetValue(designer))
            End If
        Next
    End Sub
End Class

Points of Interest

While working on this article, I discovered that one can set the properties of BasePage class (custom Page class which all pages derive from) using the Property Grid in WebForms Designer.

Future enhancements and feedback

I am planning to do the following enhancements when time permits:

  • Creating a new property called "UserControl" in UserControlDesigner, which lists all the UserControls in the Page. User can pick the UserControl he wants to bind to the designer from the dropdown.
  • Creating a custom CodeDOMSerializer for the designer which automatically generates the binding code.

Feel free to email me your suggestions and comments. I would like to make improvements based on your feedback.

History

  • 3/21/05 - Version 1.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here