Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

A Custom Copy Control - Copies Any ASP.NET Control

3.75/5 (3 votes)
11 Mar 2010CPOL2 min read 1   356  
A custom control that targets any ASP.NET control and renders it

Introduction

In this article, I have tried developing a sample custom control that simulates the functionality of copying an ASP.NET control and making it appear in another place of the page. The CopyControl can target any control say a button, panel or grid and make it appears once again in its place.

Before going into the code, I like to give a brief history about what made me think of this control. In my current project, I created a custom toolbar for my Crystal reports and placed it at the top of every report in many pages. Unfortunately, I haven't put it as a Usercontrol. As usual, a change request came from my good client asking to put the control both at the top and bottom of the reports.

Because the toolbar has many functionalities like exporting, printing it will be really a time consuming task to write the code again also. I don't want to bring the UserControl at this point. So I thought of something like creating a deep copy of the toolbar and placing the copy at the bottom. I spent some hours and finally understood that creating a deep copy of ASP.NET controls is not easy:), one of the reasons is that they are not serializable. That made me think in a different angle - why don't we render the control at two places? And.. that's the CopyControl.

The CopyControl does the trick by rendering the target control on its Rendering time.

Let's look at some code.

Bits of Code

The CopyControl can copy any target ASP.NET control. We need a property in the control for setting the target control id:

C#
[Description("Set the Target ControlId to be copied"),
Category("Behavior")]
public String TargetControlID
{
    get
    {
        if (ViewState["TargetControlId"] != null)
            return ViewState["TargetControlId"].ToString();
        return String.Empty;
    }
    set
    {
        ViewState["TargetControlId"] = value;
    }
}

We are maintaining the TargetControlID in the ViewState.

Then in the Render method of our CopyControl, we are getting the Target Control from the page and calling the RenderControl() on it. We have a private property and method for supporting it. Let's see them:

C#
private Control TargetControl
{
    get
    {
        return FindControlHelper(TargetControlID);
    }
} 
C#
private Control FindControlHelper(String controlId)
{
    Control targetControl = Page.Controls.OfType<HtmlForm>().
	FirstOrDefault().FindControl(TargetControlID) as Control;
    return targetControl;
} 
C#
protected override void Render(HtmlTextWriter writer)
{
    if (TargetControl != null)
    {
        TargetControl.RenderControl(writer);
    }
}

The FindControlHelper() gets our target control that has to be copied from the Page and returns it. Finally, we are overriding the Render() of the custom control calling the RenderControl() on the target control.

I have created the CopyControl as a separate assembly. That can be easily referenced in any page like below:

ASP.NET
<%@ Register Assembly="CopyControl" Namespace="CopyControl" TagPrefix="C" %> 

Let's say we have a panel having many child controls:

ASP.NET
<asp:Panel ID="controlPanel" runat="server">
    <table>
        <tr>
            <td>
                <asp:Button ID="newButton" Text="New" runat="server" 
		onmouseout="HighLight(this);"
                  onmouseover="HighLight(this);" CssClass="button" 
		OnClick="newButton_Click" />
            </td>
            <td>
                <asp:Button ID="deleteButton" Text="Delete" 
		runat="server" onmouseout="HighLight(this);"
                 	onmouseover="HighLight(this);" CssClass="button" />
            </td>
            <td>
                <asp:Button ID="refershButton" Text="Refresh" runat="server" 
		onmouseout="HighLight(this);"
                 	onmouseover="HighLight(this);" CssClass="button" />
            </td>
            <td>
                 <Pager:AlphapheticalFilterControl ID="alphapheticalFilterControl" 
		runat="server" DisplayCharactersLength="15" 
		SelectedCssClass="selected" ButtonCssClass="button"
                     ArrowKeyCssClass="button" />
            </td>
        </tr>
    </table>
</asp:Panel>  

You want this panel to appear in two places, say at the top and bottom of a grid. Then just drop a CopyControl at the bottom of the grid setting its TargetControlID to the panel's id.

ASP.NET
<C:CopyControlExtender TargetControlID="controlPanel" runat="server" />

That's all.

Points of Interest

By dropping more than one CopyControl on the page, we can make a control appear in two or more places on a page doing all the same functionalities.

History

  • 11th March, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)