Microsoft & .NETASPASP.NET Tip: Creating a Form Using PlaceHolder Controls

ASP.NET Tip: Creating a Form Using PlaceHolder Controls

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Previous tips explained how to use a Repeater control to build a dynamic form containing some number of text box controls. However, you may have a case in which you want to use a different control, such as a check box, in addition to the text boxes. In this case, you’ll need to use a PlaceHolder control. You can think of a PlaceHolder control as an empty container to which you can add your controls. ASP.NET will remember the values for your dynamic controls; however, you do have to create the controls both on non-postback and postback calls. Once the controls are created in postback mode, ASP.NET will re-associate the posted data with the dynamic controls and repopulate the data automatically.

This example has a table called Parameters that has the following fields to help you determine how to build the table:

Field Description
pkParameterID Primary key
Prompt Text to display next to control
DataType Text field with the value ‘String’ or ‘TF’ in it (This will let you determine which control to show.)

You also could add extra fields indicating whether the field was required, a minimum/maximum length, and so forth, but this example is designed to show just the use of the PlaceHolder control.

You then can create a simple form like this one:

<%@ Page Language="C#" AutoEventWireup="true"
                       CodeFile="test.aspx.cs" Inherits="test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-
                transitional.dtd">
<html  >
<head runat="server">
   <title>Untitled Page</title>
</head>
<body>
   <form id="form1" runat="server">
   <div>
      <asp:Repeater ID="rptFields" runat="server">
         <HeaderTemplate>
         <table>
         </HeaderTemplate>
         <ItemTemplate>
            <tr>
               <td><%# Eval("Prompt") %>:</td>
               <td><asp:PlaceHolder ID="plControl" runat="server" />
               <input type="hidden" id="hdnFieldID"
                  runat="server"
                  value='<%# Eval("pkParameterID") %>' /></td>
            </tr>
         </ItemTemplate>
         <FooterTemplate>
         </table>
         </FooterTemplate>
      </asp:Repeater>
      <p align="center"><asp:LinkButton ID="btnSubmit"
         runat="server">Submit Data</asp:LinkButton></p>
   </div>
   </form>
</body>
</html>

The code behind for this page looks like this:

public partial class test : System.Web.UI.Page
{
   protected override void OnInit(EventArgs e)
   {
      base.OnInit(e);
      rptFields.ItemDataBound +=
         new RepeaterItemEventHandler(rptFields_ItemDataBound);
   }
   protected void Page_Load(object sender, EventArgs e)
   {
      Database db = new Database("(local)", "test", "sa", "dev1227");
      AddControls(db);
      db.Close();
   }
   private void AddControls(Database db)
   {
      DataTable dt = db.GetDataTableAdhoc("SELECT * FROM Parameters
                                           ORDER BY pkParameterID");
      rptFields.DataSource = dt;
      rptFields.DataBind();
   }
   void rptFields_ItemDataBound(object sender, RepeaterItemEventArgs e)
   {
      if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType
          != ListItemType.AlternatingItem)
         return;
      DataRow dr = ((DataRowView)e.Item.DataItem).Row;
      PlaceHolder pl = (PlaceHolder)e.Item.FindControl("plControl");
      switch (dr["DataType"].ToString().ToLower())
      {
         case "string":
            TextBox txt = new TextBox();
            txt.ID = "txtField" + dr["pkParameterID"].ToString();
            pl.Controls.Add(txt);
            break;
         case "tf":
            CheckBox chk = new CheckBox();
            chk.ID = "chkField" + dr["pkParameterID"].ToString();
            pl.Controls.Add(chk);
            break;
      }
   }
}

As you see in the Page_Load routine, you need to load the dynamic controls every time—not just on the initial load of the page. I create an instance of my Database class, which encapsulates all my database code. Replace this with your favorite data access routine, but the sample uses a DataTable holding the contents of the Parameters table, which is bound against the Repeater control.

The ItemDataBound event does the bulk of the work here. It first determines that you are looking at an ItemTemplate (or AlternatingItemTemplate), and then it grabs the DataRow from the event arguments. This row holds the data type for the parameter, and a switch statement lets you get to the right area to add the right control. In each case, you instantiate a control of the appropriate type (TextBox vs. CheckBox) and then add it to the placeholder control (held in the pl variable). This causes the control to be displayed to the user.

If you wanted to give the control a default value, you’d need to check whether you were in postback mode prior to putting the value into the control or checking the box by default. If you didn’t do this check, you’d essentially erase the user’s input each time.

In the test page, you can type your data in and then press the Submit button. The Submit button will reload the page, which will show you that the values you typed in are repopulated automatically via the page’s view state. This is a handy technique for building dynamic forms, especially those driven from user-configurable data.

About the Author

Eric Smith is the owner of Northstar Computer Systems, a Web-hosting company based in Indianapolis, Indiana. He is also a MCT and MCSD who has been developing with .NET since 2001. In addition, he has written or contributed to 12 books covering .NET, ASP, and Visual Basic. Send him your questions and feedback via e-mail at questions@techniquescentral.com.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories