This article will demonstrate how y'all tin can design and build flexibility into your ASP.NET pages by calculation controls dynamically at runtime.

Yous'll acquire to add simple controls to a page, progress to adding a user command into a Placeholder command, and then accelerate to using multiple Placeholder controls to build a template page that is flexible and piece of cake to use.

Real World Applications

I'm a baseball fan. While I'd rather lookout a game in person, more often than not, I'm watching it on the television. Something that y'all may not consciously observe while watching a game on television set is the backstop. Y'all encounter it every time the camera bending from the bullpen'south point of view is displayed. Adjacent fourth dimension you're watching a baseball game on television set, keep your centre on the advertising billboard on the backstop. You will discover that the advertising changes on a regular basis. Physically at the ballpark there is a bluish screen located on the backstop and the ad is inserted existent time during the game for the boob tube viewing audition. The players, coaches, and fans at the ballpark never run across the advertizing.

Fifty-fifty experienced developers may not accept institute the need to add a control at runtime.

Yous've got to admire the marketing genius who came upwards with this idea. I tin imagine someone thinking, "If only there was a style I could sell the same billboard space to more than 1 advertiser. In that location'due south got to be a fashion!"

So why am I mentioning this in an article most dynamically adding controls at runtime to an ASP.NET folio? Because inserting different advertising messages throughout the game demonstrates exactly the blazon of thing you can do by adding controls at runtime.

Why Add Controls at Runtime?

This seems like the logical identify to start. For anyone who has already establish the need to add controls at runtime in a VB, C++, or other Win32 applications, the question may seem fairly fundamental. If you haven't experienced the need it's a very valid question. Even experienced developers may non take found the need to add a control at runtime.

So, why add controls at runtime? The main reasons are flexibility and ability. Adding controls at runtime provides the flexibility to blueprint user interfaces that can appear and behave differently to different users. Imagine a state of affairs where, depending on the security level of the currently logged on user, certain controls are displayed and others are not. Yes, you could accomplish the same functionality by setting the visible belongings of the controls but with that solution you're potentially left with unattractive spaces in the UI where the invisible controls are located. An culling solution would be to dynamically add together the controls at runtime that the user is allowed to piece of work with.

This is but one of a million different scenarios that lend themselves very well to take advantage of the flexibility and power of adding controls are runtime.

Bones ASP.Net Page Compages

Before y'all can starting time adding controls y'all need to make sure you empathise a few architectural issues. ASP.NET pages are built from controls. Everything on the page is a command. Labels, textboxes, control buttons, datagrids, static text, and fifty-fifty the HTMLForm, are represented by a control.

The Page.Controls collection contains a reference to every control contained on a page.

          Private Sub cmdSave_Click( _     ByVal sender As System.Object, _     ByVal e As System.EventArgs) _     Handles cmdSave.Click         Dim oControl As Control         For Each oControl In Page.Controls             Me.ControlsList(oControl)         Next Finish Sub  Private Sub ControlsList(ByVal oPassed As Object)      Dim oControl As Control      Response.Write("Container:"+oPassed.ID+"<P>")      For Each oControl In oPassed.Controls          Response.Write(oControl.ID + "<P>")      Next End Sub                  

The in a higher place ii procedures contain lawmaking that loops through the controls on a form and displays the ID holding. The cmdSave_Click loops through the Controls collection on the page and passes each control to the ControlsList procedure, which loops through a container control and lists all the controls.

Adding Controls Programmatically

You add controls to a page (or other container controls every bit yous'll encounter shortly) past adding controls to the Controls drove. That seems pretty straightforward to me. You telephone call the Add() method to add a command to the Controls collection. The Add together() method causes the command to be appended to the cease of the Controls collection. Y'all can add a control to a specific location in the Controls drove by using the AddAt() method.

          Private Sub Page_Load(_    ByVal sender As Organization.Object, _    ByVal e As Arrangement.EventArgs) _    Handles MyBase.Load     Dim i Every bit Integer    For i = one To 5      Controls.Add(New LiteralControl("Cool<br>"))    Next End Sub                  

The to a higher place code adds 5 Literal controls that each brandish the give-and-take Cool on the page. The resulting Web page appears in Effigy 1.

Figure 1: Web page created by adding five Literal controls at runtime.
Effigy 1: Spider web page created by adding v Literal controls at runtime.

Removing Controls Programmatically

It seems logical to me that if yous can add controls at runtime you should be able to remove them as well. And you can. Use the Remove method to remove the control yous pass to it.

          Private Sub Page_Load(_    ByVal sender As System.Object, _    ByVal eastward As System.EventArgs) _    Handles MyBase.Load     Dim i Equally Integer    For i = 1 To five      Controls.Add(New LiteralControl("Cool<br>"))    Adjacent      Controls.Remove(Controls(1))    Controls.Remove(Controls(ii)) End Sub                  

Two of the Literal controls merely added are removed in the code higher up.

ASP.Internet pages are congenital from controls. Everything on the page is a control. Labels, textboxes, command buttons, datagrids, static text, and fifty-fifty the HTMLForm, are represented past a command.

Calling a drove'south Clear method will remove all of the controls in the collection.

Introducing the Placeholder Control

While the Add method is great for adding a command at runtime, it doesn't offer you a lot of assist in designating where the command will appear on the page.

The Placeholder control is an invisible container used to shop dynamically added controls for a page. You utilise the Placeholder.Controls drove to add, insert, or remove a control from the PlaceHolder control.

          Dim MyButton1 As HtmlButton = New HtmlButton() MyButton1.InnerText = "My button" MyPlaceholder.Controls.Add together(MyButton)                  

The code above declares an HTMLButton object, assigns a value to a property, and adds it to a Placeholder control named MyPlaceholder. Of course this code assumes y'all've added a Placeholder named MyPlaceholder on your Web Form.

As yous can see, calculation controls to a placeholder at runtime is a pretty simple and powerful concept. Let's have it a step farther to where the existent power of this control becomes apparent. Instead of adding a single control or 2, let'southward add a user control.

Dynamically Adding User Controls

To start, you'll create a new Spider web Grade and you lot'll add 3 controls: a descriptive characterization, a button that will incorporate the code to add the user control, and a Placeholder control (come across Figure two).

Figure 2: The PlaceholderDemo page contains the phDemo Placeholder control and the button that adds a user control to phDemo.
Figure 2: The PlaceholderDemo page contains the phDemo Placeholder control and the button that adds a user control to phDemo.

Next, you'll create a user command named PlaceHolderDemoUserControl that you'll dynamically add to the page you just created. The user command consists of an HTML table and Web controls to create a typical data entry grade (see Figure 3).

Figure 3: The PlaceholderDemoUserControl that will be loaded into the phDemo placeholder control at runtime.
Figure three: The PlaceholderDemoUserControl that will be loaded into the phDemo placeholder control at runtime.

With your user command created information technology's time to write the code that will add it to your form at runtime (run across Listing 1).

There are three key lines in Listing 1. The kickoff creates the oCtrlDemo variable.

          Public oCtrlDemo Equally Control                  

The oCtrlDemo variable is the command that is added to the Placeholder control. The 2nd line loads the user control into the oCtrlDemo variable.

          Me.oCtrlDemo = _    LoadControl("PlaceholderDemoUserControl.ascx")                  

And the 3rd fundamental line adds the oCtrlDemo control into the phDemo placeholder.

          Me.phDemo.Controls.Add(Me.oCtrlDemo)                  

That's information technology. When the user clicks on the button the PlaceholderDemoUserControl is loaded into the oCtrlDemo command and so it is added to the phDemo placeholder by calling the Add method on the phDemo Controls collection.

While the Add method is smashing for adding a control at runtime, it doesn't offer yous a lot of help in designating where the control volition appear on the folio.

Sooner or afterwards you are going to want to reference properties on the user control. Working with properties native to the Control grade that the oCrtlDemo control is based on is very straightforward. Yous only assign or retrieve the property value like you would with any other object.

          Private Sub Button1_Click(_   ByVal sender Every bit System.Object, _   ByVal e As System.EventArgs) _   Handles Button1.Click    Me.oCtrlDemo = _     LoadControl("PlaceholderDemoUserControl.ascx")    Me.oCtrlDemo.Visible = False    Me.phDemo.Controls.Add(Me.oCtrlDemo) Finish Sub                  

You can see in the code above that the Visible property of the oCtrlDemo object has been set to False. Since Visible is a native property of the Control grade this will work fine. The end issue of this code is that the oCtrlDemo control will exist added to the placeholder simply it will not be visible.

Working with the properties native to the Control course is all well and good, but let's add a custom property named DemoProp to the PlaceholderDemoUserControl (run into List 2). It just takes a simple step in order to access the DemoProp property. Yous'll covert the oCtrlDemo form to the type of class you lot added to it, namely the PlaceholderDemoUserControl. The following lawmaking demonstrates how to practise this.

          Private Sub Button1_Click(_   ByVal sender As System.Object, _   ByVal e As Organization.EventArgs) _   Handles Button1.Click    Me.oCtrlDemo = _     LoadControl("PlaceholderDemoUserControl.ascx")    CType(Me.oCtrlDemo, _     PlaceholderDemoUserControl).DemoProp = ten    Me.phDemo.Controls.Add(Me.oCtrlDemo) Terminate Sub                  

In this lawmaking, the key is to make certain that you catechumen the oCtrlDemo object from a plain Control object into an object of type PlaceholderDemoUserControl, then yous'll utilize the CTYPE() role. Once y'all're washed you can admission the custom property, DemoProp.

I'll suggest one more modify here just to drive home the betoken of working with backdrop on user controls. In this next lawmaking snippet, I'll add a line to the Page_Load method of the PlaceholderDemoControl user command that volition set the Age textbox to the value in the DemoProp property.

          Private Sub Page_Load(_     ByVal sender As System.Object, _     ByVal e As System.EventArgs) _     Handles MyBase.Load         Me.txtAge.Text = Me.DemoProp Cease Sub                  

As y'all've seen so far, working with the Placeholder control and dynamically calculation controls at runtime is non that difficult. Adjacent, yous can accept what you've learned and extend it into a page template.

Dynamically Populating a Template Folio

You lot're probably beginning to meet the potential flexibility in this technique. Yous tin take this idea even farther and instead of a single placeholder control on a Web Course, permit'south create an HTML tabular array with a header placeholder control beyond the top (plhHeader), a footer placeholder control across the lesser (plhFooter), a navigation placeholder down the left hand side of the form (plhNavigation), and finally a body placeholder in the heart (plhBody). You'll name this Web Course FormTemplate.aspx (see Effigy 4).

Figure 4: The FormTemplate.aspx page contains four different placeholder controls laid out in an HTML table.
Effigy 4: The FormTemplate.aspx page contains iv different placeholder controls laid out in an HTML table.

You'll also need to build the user controls that y'all'll add to the template. You'll add the Header.ascx user control (see Effigy 5) to the plhHeader placeholder control. You'll add the Footer.ascx user control (come across Effigy half-dozen) to the plhFooter placeholder. And (yous guessed it) you'll add the Navigation.ascx user command (Effigy 7) to the plhNavigation placeholder control. You'll apply a few different user controls to display the content for the body section (plhBody) of the template (see Figures 8, 9, & 10).

Figure 5: The Header.ascx user control will be used to populate the plhHeader placeholder on the FormTemplate Web Form.
Effigy 5: The Header.ascx user control will be used to populate the plhHeader placeholder on the FormTemplate Web Form.
Figure 6: The Footer.ascx user control will be used to populate the plhFooter placeholder on the FormTemplate Web Form.
Effigy vi: The Footer.ascx user control volition be used to populate the plhFooter placeholder on the FormTemplate Web Form.
Figure 7: The Navigation.ascx user control will be used to populate the plhNavigation placeholder on the FormTemplate Web Form.
Figure 7: The Navigation.ascx user control volition be used to populate the plhNavigation placeholder on the FormTemplate Web Form.
Figure 8: The Body.ascx user control is one of three user controls used to populate the plhBody placeholder on the FormTemplate Web Form.
Figure eight: The Body.ascx user control is i of three user controls used to populate the plhBody placeholder on the FormTemplate Web Form.
Figure 9: The Body2.ascx user control is one of three user controls used to populate the plhBody placeholder on the FormTemplate Web Form.
Figure 9: The Body2.ascx user control is one of three user controls used to populate the plhBody placeholder on the FormTemplate Web Form.
Figure 10: The Body3.ascx user control is one of three user controls used to populate the plhBody placeholder on the FormTemplate Web Form.
Figure 10: The Body3.ascx user control is 1 of three user controls used to populate the plhBody placeholder on the FormTemplate Spider web Grade.

Listing 3 contains the complete grade definition for the FormTemplate Web Form course. In add-on to the Page_Load method you will find four additional methods that are each responsible for loading a specific placeholder command.

The HeaderSetup method accepts no arguments and adds the Header.ascx user control to the plhHeader placeholder. The FooterSetup method accepts no arguments and adds the Footer.ascx user control to the plhFooter placeholder. The NavigationSetup accepts no arguments and adds the Navigation.ascx user control to the plhNavigation placeholder. Yous could easily extend these methods to accept an statement that specifies exactly which user control to add. That is exactly how the body content of the folio is controlled. The BodySetup method accepts one string argument (strCode) and adds one of the Body user controls (Torso.ascx, Body2.ascx, or Body3.ascx) to the plhBody placeholder depending on the value contained in strCode.

When the page loads for the first time, the Trunk query string variable volition exist blank and will result in neither of the body user controls being added (come across Figure 11). In this situation you could load a "dwelling house" user control to brandish the initial content. I'll go out that equally an exercise for you.

Figure 11: The FormTemplate page that displays when a Body query string variable is not passed in.
Effigy eleven: The FormTemplate page that displays when a Body query string variable is not passed in.

So, how does the Body query string variable become set up? The links in the Navigation user control agree the respond to this question.

          <asp:LinkButton id="LinkButton1" runat="server"  CommandArgument="1">Body #1</asp:LinkButton>  <asp:LinkButton id="Linkbutton2" runat="server" CommandArgument="2">Torso #two</asp:LinkButton>  <asp:LinkButton id="Linkbutton2" runat="server" CommandArgument="two">Body #2</asp:LinkButton>                  

Setting the CommandArgument for each LinkButton to 1, 2, or 3 determines which Body user control to display. In addition, each LinkButton has its Click event handled past the FilterLetter_Click method.

          Private Sub FilterLetter_Click(_    ByVal sender As System.Object, _    ByVal due east As System.EventArgs) _    Handles LinkButton1.Click, _            Linkbutton2.Click, _            Linkbutton3.Click     If sender.CommandArgument = 1 So      Response.Redirect("Formtemplate.aspx?Trunk=1")    ElseIf sender.CommandArgument = ii Then      Response.Redirect("Formtemplate.aspx?Torso=two")    ElseIf sender.CommandArgument = 3 And then      Response.Redirect("Formtemplate.aspx?Body=3")    Finish If End Sub                  

In this lawmaking the FormTemplate page is posted to and the Trunk query string gets passed into information technology.

Contained in the Page_Load is where the Torso query string is captured and later on passed into the BodySetup method.

          Dim strBodyCode As String = _     Request.QueryString("Trunk")  Me.HeaderSetup() Me.FooterSetup() Me.NavigationSetup() Me.BodySetup(strBodyCode)                  

Let's walk through a typical user action. Clicking on the Body #3 LinkButton on the Navigation bar causes a "3" to exist posted dorsum to the FormTemplate page. This in plough causes a "3" to be passed into the BodySetup method causing the Body3.ascx user control to be loaded into the plhBody placeholder. The resulting page is in Figure 12.

Figure 12: The FormTemplate page that displays when the Body query string variable is set to 3.
Figure 12: The FormTemplate folio that displays when the Body query string variable is set to 3.

Obviously the template you created here is just one of an infinite number of templates you can design and build yourself for your ASP.Net Web sites.

Decision

Well that wraps up this article. I'm always interested to hear your feedback about the material covered hither. As you can run across, working with the Placeholder command and adding controls at runtime provides you lot with the flexibility to design generic templates and the power to leverage them over and over again.

Listing 1: Class lawmaking for the PlaceholderDemo.aspx Web Form

            Public Class PlaceholderDemo     Inherits <a href="http://System.Web.UI">System.Web.UI</a>.Page       Public oCtrlDemo As Control      Protected WithEvents Label1 As _         <a href="http://System.Web.UI">System.Web.UI</a>.WebControls.Label     Protected WithEvents phDemo As _         <a href="http://Arrangement.Spider web.UI">Organisation.Web.UI</a>.WebControls.PlaceHolder     Protected WithEvents Button1 Every bit _         <a href="http://Organization.Web.UI">System.Web.UI</a>.WebControls.Push button      Individual Sub Page_Load(_        ByVal sender As System.Object, _        ByVal eastward Every bit System.EventArgs) _        Handles MyBase.Load         'Put user lawmaking to initialize the page here     End Sub      Private Sub Button1_Click(_        ByVal sender As System.Object, _        ByVal e As Organization.EventArgs) Handles Button1.Click         Me.oCtrlDemo = _            LoadControl("PlaceholderDemoUserControl.ascx")         Me.phDemo.Controls.Add together(Me.oCtrlDemo)     Terminate Sub End Grade                      

Listing two: Grade code for the PlaceholderDemoUserControl.ascx user control

            Public Form PlaceholderDemoUserControl     Inherits <a href="http://System.Web.UI">System.Web.UI</a>.UserControl     Protected WithEvents Label1 Every bit _         <a href="http://System.Web.UI">Arrangement.Web.UI</a>.WebControls.Label     Protected WithEvents txtFirstName As _         <a href="http://System.Spider web.UI">System.Web.UI</a>.WebControls.TextBox     Protected WithEvents Label2 Equally _         <a href="http://System.Web.UI">System.Web.UI</a>.WebControls.Label     Protected WithEvents txtLastName As _         <a href="http://System.Web.UI">System.Web.UI</a>.WebControls.TextBox     Protected WithEvents Label3 Every bit _         <a href="http://System.Web.UI">Arrangement.Web.UI</a>.WebControls.Characterization     Protected WithEvents txtAge As _         <a href="http://Organisation.Web.UI">Organisation.Spider web.UI</a>.WebControls.TextBox      Private m_MyProperty Every bit Integer      Public Property DemoProp() Every bit Integer         Become             Return m_MyProperty         Finish Get          Set(ByVal MyValue As Integer)             m_MyProperty = MyValue         End Set up     End Property      Private Sub Page_Load(_        ByVal sender As Organisation.Object, _        ByVal e Equally Organisation.EventArgs) Handles MyBase.Load         'Put user code to initialize the folio here     Stop Sub End Class                      

Listing three: Class code for the FormTemplate.aspx Spider web Form

            Public Class FormTemplate     Inherits <a href="http://System.Spider web.UI">Arrangement.Web.UI</a>.Page      Protected WithEvents plhHeader Every bit _         <a href="http://System.Web.UI">System.Spider web.UI</a>.WebControls.PlaceHolder     Protected WithEvents plhNavigation As _         <a href="http://Arrangement.Web.UI">System.Web.UI</a>.WebControls.PlaceHolder     Protected WithEvents plhBody Equally _         <a href="http://System.Web.UI">System.Spider web.UI</a>.WebControls.PlaceHolder     Protected WithEvents plhFooter Equally _         <a href="http://System.Web.UI">System.Spider web.UI</a>.WebControls.PlaceHolder      Private Sub Page_Load(_        ByVal sender As Organization.Object, _        ByVal eastward As Organisation.EventArgs) Handles MyBase.Load          Dim strBodyCode As String = _             Request.QueryString("Torso")          Me.HeaderSetup()         Me.FooterSetup()         Me.NavigationSetup()         Me.BodySetup(strBodyCode)      End Sub      Private Sub HeaderSetup()         Dim oMyControl Every bit Control         oMyControl = LoadControl("Header.ascx")          Me.plhHeader.Controls.Clear()         Me.plhHeader.Controls.Add(oMyControl)     End Sub      Individual Sub BodySetup(ByVal strCode As String)         Dim oMyControl Equally Command          If strCode = "one" Then             oMyControl = LoadControl("Body.ascx")         ElseIf strCode = "2" Then             oMyControl = LoadControl("Body2.ascx")         ElseIf strCode = "three" And then             oMyControl = LoadControl("Body3.ascx")         Cease If          If Not strCode Is Cypher Then             Me.plhBody.Controls.Articulate()             Me.plhBody.Controls.Add together(oMyControl)         Stop If     End Sub      Private Sub FooterSetup()         Dim oMyControl Every bit Control         oMyControl = LoadControl("Footer.ascx")          Me.plhFooter.Controls.Clear()         Me.plhFooter.Controls.Add together(oMyControl)     End Sub      Individual Sub NavigationSetup()         Dim oMyControl Equally Control         oMyControl = LoadControl("Navigation.ascx")          Me.plhNavigation.Controls.Clear()         Me.plhNavigation.Controls.Add(oMyControl)     End Sub End Class