Adding Controls to a Page
You can add new controls to a page by adding the controls to a page's Controls collection. You can add a control at the end of the Controls collection by using the Add() method. Alternatively, you can add a control at a specific index location in the Controls collection by using the AddAt() method.
The page in Listing 4.9, for example, constructs all its own controls. It contains a single Page_Load subroutine, which adds 30 LiteralControl controls to the page. If you open this page in your Web browser, you see the word Hello! repeated 30 times (see Figure 4.5).
Listing 4.9 ControlsAdd.aspx
<Script Runat="Server"> Sub Page_Load Dim intCounter As Integer For intCounter = 1 To 30 Controls.Add( New LiteralControl( "Hello!" ) ) Next End Sub </Script>
Figure 4.5. Self-building page.
You can remove controls from the Controls collection by using the Remove(), RemoveAt(), or Clear() method. The Remove() method removes the control that you pass to it, the RemoveAt() method removes a control at a specific index location, and the Clear() method removes all the controls from the Controls collection.
The page in Listing 4.10, for example, adds three controls and then uses the Remove() method to remove the first control.
Listing 4.10 ControlsRemove.aspx
<Script Runat="Server"> Sub Page_Load Dim intCounter As Integer For intCounter = 1 To 3 Controls.Add( new LiteralControl( "Control" & intCounter ) ) Next Controls.Remove( Controls.Item( 0 ) ) End Sub </Script>
The PlaceHolder Control
Typically, you don't add controls directly to a page's Controls collection. In most cases, you will want to add a control to a particular location on a page.
You can add a control to the Controls collection of any other control. For example, there is nothing wrong with adding a new control to the Controls collection of either an HTMLForm or Panel control.
However, there is a special control included in the ASP.NET Framework, called the PlaceHolder control that has the singular purpose of acting as a container for other controls.
Listing 4.11 illustrates how you can use the PlaceHolder control to dynamically add TextBox controls to a form.
Listing 4.11 PlaceHolder.aspx
<Script Runat="Server"> Sub Page_Load Dim intCounter As Integer Dim btnNewButton As Button For intCounter = 1 to 10 plhPlaceHolder.Controls.Add( _ New LiteralControl( "<p>Field " & intCounter & ": " ) ) plhPlaceHolder.Controls.Add( _ New TextBox ) Next btnNewButton = New Button btnNewButton.Text = "Click Here!" plhPlaceHolder.Controls.Add( btnNewButton ) End Sub </Script> <html> <head><title>PlaceHolder.aspx</title></html> <body> <form Runat="Server"> <asp:PlaceHolder id="plhPlaceHolder" Runat="Server" /> </form> </body> </html>
In the Page_Load subroutine in Listing 4.11, ten TextBox controls and one Button control are added to the Controls collection of a PlaceHolder control. When the page is displayed in a browser, the new TextBox controls are rendered.
Dynamically Generating Forms
Imagine that you need to create a form that has a variable number of input fields. For example, you can imagine a simple order entry form that enables you to enter a variable number of product orders. The same form enables you to submit a single order or 25 orders at a time.
You can use the methods discussed in the previous section to dynamically add form fields to a form. Listing 4.12 contains a simple order entry form. When the page first loads, it contains a single form field for the customer name and a single form field for the product.
The page also contains a button labeled Add Product Field. When you click this button, a new product form field is added to the form. You can click this button as many times as you wish to add any number of new product form fields (see Figure 4.6).
Figure 4.6. Dynamically generated form.
When you click the Add Product Field button, the AddProductFieldCount subroutine is executed. This subroutine increments the count of product fields (stored in the state bag) by one. It also adds a new text box to the page by calling the AddProductField subroutine.
Notice that the Page_Load subroutine rebuilds all the product fields every time the page is loaded. When you dynamically add a new control to a page, the control is not automatically retained between form posts. The control itself is not preserved in the page's view state. However, any text you enter into a dynamically generated form field is automatically preserved in view state.
Listing 4.12 DynamicForm.aspx
<Script Runat="Server"> Sub Page_Load Dim intCounter As Integer If Not IsPostBack Then ViewState( "ProductFieldCount" ) = 1 ElseIf ViewState( "ProductFieldCount" ) > 1 Then For intCounter = 2 To ViewState( "ProductFieldCount" ) AddProductField( intCounter ) Next End If End Sub Sub AddProductFieldCount( s As Object, e As EventArgs ) ViewState( "ProductFieldCount" ) += 1 AddProductField( ViewState( "ProductFieldCount" ) ) End Sub Sub AddProductField( strFieldNum As String ) Dim litLabel As LiteralControl Dim txtTextBox As TextBox ' Add Literal Control litLabel = New LiteralControl litLabel.Text = "<p><b>Product " & strFieldNum & ":</b> " plhProductFields.Controls.Add( litLabel ) ' Add TextBox Control txtTextBox = New TextBox txtTextBox.ID = "txtProduct" & strFieldNum plhProductFields.Controls.Add( txtTextBox ) End Sub Sub btnSubmit_Click( s As Object, e As EventArgs ) Response.Redirect( "ThankYou.aspx" ) End Sub </Script> <html> <head><title>DynamicForm.aspx</title></html> <body> <form Runat="Server"> <b>Customer Name:</b> <asp:TextBox ID="txtCustomer" Runat="Server" /> <p> <div style="background-color: yellow;padding:10px"> <b>Product 1:</b> <asp:TextBox ID="txtProduct1" Runat="Server" /> <asp:PlaceHolder id="plhProductFields" Runat="Server" /> </div> <p> <asp:Button Text="Add Product Field" OnClick="AddProductFieldCount" Runat="Server" /> <asp:Button id="btnSubmit" Text="Submit Complete Order" OnClick="btnSubmit_Click" Runat="Server" /> </form> </body> </html>