Recipe 5.6. Adding User Controls Dynamically


Problem

You need to load a group of user controls programmatically at runtime because the number of controls required is unknown at design time.

Solution

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 ItemDataBound event to load a user control dynamically 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:

  1. Bind the data to the Repeater control.

  2. Create an event handler method for the ItemDataBound event of the Repeater control.

  3. In the method that handles the ItemDataBound event, use the LoadControl method to create an instance of the user control, and then add the loaded control to the controls collection of the table cell in the ItemTemplate.

Figure 5-5 shows a form where we start with the user controls created in Recipe 5.4 and dynamically load three user controls at runtime. Example 5-26 shows the .aspx file that implements this solution, while Examples 5-27 and 5-28 show the companion VB and C# code-behind files.

Discussion

This recipe demonstrates how to load a group of user controls dynamically 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 templatedriven. 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 5.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.

Figure 5-5. User controls loaded at runtime output


A 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 5-26 shows how we've implemented this in our example.

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 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.

To demonstrate the multicast event mechanism in .NET we mentioned in Recipe 5.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 CH05UserControlCommSourceCS.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, which is a bit dull. Imagining a more interesting scenario is easy 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.

See Also

Recipe 5.4

Example 5-26. User controls loaded at runtime (.aspx)

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master" AutoEventWireup="false" CodeFile="CH05UserControlRuntimeVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH05UserControlRuntimeVB" Title="Load User Controls At Runtime" %> <%@ Register TagPrefix="ASPCookbook" TagName="SourceControl"  src="/books/1/505/1/html/2/CH05UserControlCommSourceVB.ascx" %> <asp:Content  Runat="server" ContentPlaceHolder> <div align="center" > Load User Controls At Runtime (VB) </div> <table width="90%" align="center" border="0" > <tr> <td  colspan="2"> Source User Control:</td> </tr> <tr> <td bgcolor="#ffffcc" align="center" height="50" colspan="2"> <ASPCookbook:SourceControl  runat="server" /> </td> </tr> <tr> <td colspan="2">&nbsp;</td> </tr> <tr> <td  colspan="2"> User Controls Loaded At Runtime: </td> </tr> <asp:repeater  runat="server" OnItemDataBound="repUserControls_ItemDataBound"> <itemtemplate> <tr  runat="server" height="50"> <td  runat="server" width="10%"></td> <td  runat="server"></td> </tr> </itemtemplate> </asp:repeater> </table> </asp:Content> 

Example 5-27. User controls loaded at runtime (.vb)

 Option Explicit On Option Strict On Imports System.Web.UI.WebControls Namespace ASPNetCookbook.VBExamples ''' <summary> ''' This class provides the code behind for ''' CH05UserControlRuntimeVB.aspx ''' </summary> Partial Class CH05UserControlRuntimeVB Inherits System.Web.UI.Page 'the following variable is used to keep count of the number of controls Private controlCount As Integer '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the page load event. It ''' is responsible for initializing the controls on the page. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub Page_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.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 '''*********************************************************************** ''' <summary> ''' 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. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub repUserControls_ItemDataBound(ByVal sender As Object, _ ByVal e As RepeaterItemEventArgs) '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 CH05UserControlCommDestinationVB '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("CH05UserControlCommDestinationVB.ascx"), _ CH05UserControlCommDestinationVB) cell.Controls.Add(ucDest) AddHandler ucSource.OnSend, AddressOf ucDest.updateLabel End If End Sub 'repUserControls_ItemDataBound End Class 'CH05UserControlRuntimeVB End Namespace 

Example 5-28. User controls loaded at runtime (.cs)

 using System; using System.Collections; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { /// <summary> /// This class provides the code behind for /// CH05UserControlRuntimeCS.aspx /// </summary> public partial class CH05UserControlRuntimeCS : System.Web.UI.Page { // the following variable is used to keep count of the number of controls private int controlCount; ///*********************************************************************** /// <summary> /// This routine provides the event handler for the page load event. /// It is responsible for initializing the controls on the page. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void Page_Load(object sender, EventArgs e) { ArrayList values = 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(); } // Page_Load ///*********************************************************************** /// <summary> /// 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. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void repUserControls_ItemDataBound(Object sender, 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; HtmlTableCell cell; CH05UserControlCommDestinationCS ucDest; // 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 = (CH05UserControlCommDestinationCS) (LoadControl("CH05UserControlCommDestinationCS.ascx")); cell.Controls.Add(ucDest); ucSource.OnSend += new   CH05UserControlCommSourceCS.customMessageHandler(ucDest.updateLabel); }  } // repUserControls_ItemDataBound } // CH05UserControlRuntimeCS } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2003
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net