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:
[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:
private Control TargetControl
{
get
{
return FindControlHelper(TargetControlID);
}
}
private Control FindControlHelper(String controlId)
{
Control targetControl = Page.Controls.OfType<HtmlForm>().
FirstOrDefault().FindControl(TargetControlID) as Control;
return targetControl;
}
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:
<%@ Register Assembly="CopyControl" Namespace="CopyControl" TagPrefix="C" %>
Let's say we have a panel having many child controls:
<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.
<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