You need to programmatically load a group of user controls at runtime because the number of controls required is not known at design time.
Bind your data to a Repeater
control
in the normal
fashion and then, as data is bound to each row of the
Repeater
, use the event to dynamically load a user
control and place it in a table cell of the
Repeater
control’s
ItemTemplate
.
Add a Repeater
control to the
.aspx
file with a table cell in the
ItemTemplate
where the user control is to be
placed.
In the code-behind class, use the .NET language of your choice to:
Bind the data to the
Repeater
control.Create an event handler method for the
ItemDataBound
event of theRepeater
control.In the method that handles the
ItemDataBound
event, use theLoadControl
method to create an instance of the user control, and then add the loaded control to the controls collection of the table cell in theItemTemplate
.
Figure 4-5 shows a simple form where we start with
the user controls created in Recipe 4.4 and dynamically load three user
controls at runtime. Example 4-24 shows the
.aspx
file that implements this solution, while
Example 4-25 and Example 4-26 show the companion VB and C# code-behind
files.
This recipe demonstrates how to dynamically load a group of user
controls into a form, the count for which can be determined only at
runtime. A Repeater
control is used because it
generates a lightweight read-only tabular display and is
template-driven. The Repeater
control’s ItemTemplate
element
formats the rows of data. The user control dynamically loaded at
runtime is strategically placed in a table cell in the
ItemTemplate
. This loading takes place in the
method that handles the ItemDataBound
event for
each row of the Repeater
. More specifically, the
LoadControl
method is used to create an instance
of the user control, and then the loaded control is added to the
controls collection of the table cell.
The example we have written to demonstrate the solution starts with the user controls created in Recipe 4.4 and loads the destination user controls at runtime. In addition, it wires them to the source user control to demonstrate the multicast event mechanism in .NET.
An ASP:Repeater
control is placed in the
.aspx
file with an
ItemTemplate
containing two table cells. The first
cell is used to hold the dynamically loaded user
control’s number, and the second cell is used to
hold the user control itself. Example 4-24 shows how
we’ve implemented this in our example.
Tip
The dynamically loaded user controls can be added to the
Page
control collection; however, this will place
them at the bottom of the page and they will be rendered outside of
the form. Dynamically loaded user controls should be added to the
controls collection of some control contained within the form.
In the repUserControls_ItemDataBound
method of the
code-behind, the user control for the row being bound is loaded at
runtime from the .ascx
file using the
LoadControl
method. It is then added to the
controls collection of the second table cell in the
Repeater
.
Just to demonstrate the multicast event mechanism in .NET that we
mentioned in Recipe 4.4, each of the
dynamically loaded user controls is wired to the source user control
in the .aspx
file. This results in each of the
dynamically loaded user controls receiving the message event from the
source user control.
AddHandler ucSource.OnSend, AddressOf ucDest.updateLabel ucSource.OnSend += new CH04UserControlCommSourceCS.customMessageHandler(ucDest.updateLabel);
The result in this case is that each destination user control is
updated with the same text from the source user control—not
very exciting. But it is not hard to imagine a more interesting
scenario where one destination user control has a text label updated,
the second a database, and the third an XML web service, or the like,
with all of these updates the result of methods having been
registered with the source control’s
OnSend
event’s event handler
list.
Example 4-24. User controls loaded at runtime (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH04UserControlRuntimeVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH04UserControlRuntimeVB" %> <%@ Register TagPrefix="ASPCookbook" TagName="SourceControl" Src="CH04UserControlCommSourceVB.ascx" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Load User Controls At Runtime</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmUCRuntime" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Load User Controls At Runtime (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table border="0" width="100%"> <tr> <td class="PageHeading" colspan="2"> Source User Control:</td> </tr> <tr> <td bgcolor="#ffffcc" align="center" height="50" colspan="2"> <ASPCookbook:SourceControl id="ucSource" runat="server" /> </td> </tr> <tr> <td colspan="2"> </td> </tr> <tr> <td class="PageHeading" colspan="2"> User Controls Loaded At Runtime:</td> </tr><asp:repeater id="repUserControls" runat="server">
<itemtemplate>
<tr id="trControl" runat="server" height="50">
<td id="tdCount" runat="server" width="10%"></td>
<td id="tdUserControl" runat="server"></td>
</tr>
</itemtemplate>
</asp:repeater>
</table> </td> </tr> </table> </form> </body> </html>
Example 4-25. User controls loaded at runtime code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH04UserControlRuntimeVB.aspx.vb ' ' Description: This module provides the code behind for ' CH04UserControlRuntimeVB.aspx ' '***************************************************************************** Imports System.Collections Imports System.Drawing Imports System.Web.UI.HtmlControls Imports System.Web.UI.WebControls Namespace ASPNetCookbook.VBExamples Public Class CH04UserControlRuntimeVB Inherits System.Web.UI.Page 'controls on the form Protected ucSource As CH04UserControlCommSourceVB Protected WithEvents repUserControls As System.Web.UI.WebControls.Repeater 'the following variable is used to keep count of the number of controls Private controlCount As Integer '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the ' controls on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load Dim values As ArrayList = New ArrayList 'build array of data to bind to repeater 'for this example it is just the color of the entry but for a real 'application the data would normally be from a database, etc. values.Add("#ffffcc") values.Add("#ccffff") values.Add("#ccff99") 'bind the data to the repeater controlCount = 0 repUserControls.DataSource = values repUserControls.DataBind( ) End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: repUserControls_ItemDataBound ' ' DESCRIPTION: This routine provides the event handler for the item ' data bound event of the repeater control on the form. ' It is responsible for loading the user control and ' placing it in the repeater for the item being bound. '------------------------------------------------------------------------- Private Sub repUserControls_ItemDataBound(ByVal sender As Object, _ ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) _ Handles repUserControls.ItemDataBound 'the following constants are the names of the controls in the repeater Const TABLE_ROW As String = "trControl" Const COUNT_CELL As String = "tdCount" Const USER_CONTROL_CELL As String = "tdUserControl" Dim row As HtmlTableRow Dim cell As HtmlTableCell Dim ucDest As CH04UserControlCommDestinationVB 'make sure this is an item or alternating item in the repeater If ((e.Item.ItemType = ListItemType.Item) Or _ (e.Item.ItemType = ListItemType.AlternatingItem)) Then 'find the table row and set the background color row = CType(e.Item.FindControl(TABLE_ROW), _ HtmlTableRow) row.BgColor = CStr(e.Item.DataItem) 'find the cell for the control count and set the count cell = CType(e.Item.FindControl(COUNT_CELL), _ HtmlTableCell) controlCount += 1 cell.InnerText = controlCount.ToString( )'find the cell for the control and load a user control
cell = CType(e.Item.FindControl(USER_CONTROL_CELL), _
HtmlTableCell)
ucDest = CType(LoadControl("CH04UserControlCommDestinationVB.ascx"), _
CH04UserControlCommDestinationVB)
cell.Controls.Add(ucDest)
AddHandler ucSource.OnSend, AddressOf ucDest.updateLabel
End If End Sub 'repUserControls_ItemDataBound End Class 'CH04UserControlRuntimeVB End Namespace
Example 4-26. User controls loaded at runtime code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH04UserControlRuntimeCS.ascx.cs // // Description: This module provides the code behind for // CH04UserControlRuntimeCS.ascx // //**************************************************************************** using ASPNetCookbook.CSExamples; using System; using System.Collections; using System.Drawing; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH04UserControlRuntimeCS : System.Web.UI.Page { // controls on the form protected CH04UserControlCommSourceCS ucSource; protected System.Web.UI.WebControls.Repeater repUserControls; // the following variable is used to keep count of the number of controls private int controlCount; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { ArrayList values = new ArrayList( ); // wire the item data bound event this.repUserControls.ItemDataBound += new RepeaterItemEventHandler(this.repUserControls_ItemDataBound); // build array of data to bind to repeater // for this example it is just the color of the entry but for a real // application the data would normally be from a database, etc. values.Add("#ffffcc"); values.Add("#ccffff"); values.Add("#ccff99"); // bind the data to the repeater controlCount = 0; repUserControls.DataSource = values; repUserControls.DataBind( ); } // Page_Load //************************************************************************ // // ROUTINE: repUserControls_ItemDataBound // // DESCRIPTION: This routine provides the event handler for the item // data bound event of the datalist control in the nav bar. // It is responsible for setting the anchor and image // attributes for the item being bound. //------------------------------------------------------------------------ private void repUserControls_ItemDataBound(Object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e) { // the following constants are the names of the controls in the repeater const String TABLE_ROW = "trControl"; const String COUNT_CELL = "tdCount"; const String USER_CONTROL_CELL = "tdUserControl"; HtmlTableRow row = null; HtmlTableCell cell = null; CH04UserControlCommDestinationCS ucDest = null; // make sure this is an item or alternating item in the repeater if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem)) { // find the table row and set the background color row = (HtmlTableRow)(e.Item.FindControl(TABLE_ROW)); row.BgColor = (String)(e.Item.DataItem); // find the cell for the control count and set the count cell = (HtmlTableCell)(e.Item.FindControl(COUNT_CELL)); controlCount += 1; cell.InnerText = controlCount.ToString( );// find the cell for the control and load a user control
cell = (HtmlTableCell)(e.Item.FindControl(USER_CONTROL_CELL));
ucDest = (CH04UserControlCommDestinationCS)
(LoadControl("CH04UserControlCommDestinationCS.ascx"));
cell.Controls.Add(ucDest);
ucSource.OnSend +=
new
CH04UserControlCommSourceCS.customMessageHandler(ucDest.updateLabel);
} } // repNavBarCell_ItemDataBound } // CH04UserControlRuntimeCS }
Get ASP.NET Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.