Practical ASP.NET

More on Adding Controls Dynamically

Peter returns to last week's topic to go beyond the basics of how to add controls to a page to fully integrate it into your Page's lifecycle.

In my most recent column, I discussed tactics for adding controls at runtime to a page, but I didn't discuss when you should do this or how to enable catching events from these controls. Before answering that question, it's worthwhile to provide some background information first. I'll walk through the lifecycle of an ASP.NET page from the time that your control is added until you access the data that the user has entered into the control.

I'll start by assuming that you've added a control using one of the techniques that I discussed either in the Page's PreRender event or some event that fires before that event. After the PreRender event, ASP.NET hands off the HTML for the page to IIS, which is responsible for getting the page back to the user. Once the page appears in the browser, the user can interact with it, probably filling in some of the controls that you've added with data.

Eventually, the user clicks on a Submit button (or triggers an AutoPostBack). At that point, the browser -- regardless of what browser is displaying the page -- gathers up all the data from the page and sends it back to the server with the name of the control that the data was displayed in. Assuming that you're not using cross page posting, this data is sent to the server with a request for the page currently displayed in the browser.

Back at the server, IIS finds the requested page. The page first rebuilds all the controls defined in the page's aspx file, which means that any controls added dynamically at run time by your code aren't added. The page then slots the data that came up from the browser into the controls, matching the control name sent up from the browser with the control's ID property. To get the data slotted into your control, therefore, you need to add your control to the page at the right moment.

The Page class has a method set aside specifically for adding controls to the page: the CreateChildControls method. ASP.NET guarantees that, no matter what mutations the Page class goes through as Microsoft extends and enhances it, the CreateChildControls method will be called at the right point in the Page's lifecycle for everything to work out for you. You just need to override the method and add your code. If you wire up an event handler to your control (e.g. a TextChanged event) in this method, the events for your control will also be fired correctly.

However, let's go in time to the point where you added the control to the page in the first place. In order to decide if you should add the control, you probably had to check the user's input: some selections the user made or some data they entered or some button they clicked. But, remember, you don't have access to any of that data until after the data is loaded into the control and, while you may not know exactly when the CreateChildControls method is called, the method has to be called before the data can be put into the control. So you need to add the control for the first time after the CreateChildControls method has been called and add the control on all subsequent occasions in the the CreateChildControls method.

The solution is to first write a method that adds your control (and, optionally, wires up any events you want to process). You then call that in some event between the Page Load and the PreRender event to add the control to the page for the first time. You should also set a flag that indicates that the control has been added. Since you only need this flag inside the page, you should store the flag in the ViewState. Then, in the CreateChildControls method you can check for that flag and, it's set, call the method to add the control back.

In the following code, I've assumed that in the Page Load event I'll check to see if a RadioButton is set to decide if a control is to be added. If the RadioButton is checked, I'll call my method that adds a TextBox control (which also wires up the TextChanged event) and sets a flag in the ViewState. In the CreateChildControls method, I check for the flag and call the same method to put the control back in place to catch the data being sent from the browser. I've also included the code to remove the control when the RadioButton isn't selected:
Dim txt As TextBox

Protected Sub Page_Load(ByVal sender As Object, _
         ByVal e As System.EventArgs) Handles Me.Load
  If Me.IsPostBack = True Then
   If Me.rdbAddControl.Checked Then
     If Me.ViewState("TextBoxAdded") <> "true" Then
       AddTextBox()
     End If
   Else
     RemoveTextBox()
   End If
  End If
End Sub

Private Sub AddTextBox()
  txt = New TextBox
  txt.ID = "AddedTextBox"
  Me.Panel1.Controls.Add(txt)
  Me.ViewState("TextBoxAdded") = "true"
  AddHandler txt.TextChanged, _
                  AddressOf AddedTextBox_TextChanged
End Sub

Private Sub RemoveTextBox()
  If Me.ViewState("TextBoxAdded") = "true" Then
     Me.ViewState("TextBoxAdded") = "false"
     RemoveHandler txt.TextChanged, _
         AddressOf AddedTextBox_TextChanged
     Me.Panel1.Controls.Remove(txt)
     Exit Sub
  End If
End Sub

Protected Overrides Sub CreateChildControls()
  If Me.ViewState("TextBoxAdded") = "true" Then
     AddTextBox()
  End If
  MyBase.CreateChildControls()
End Sub

Private Sub AddedTextBox_TextChanged( _
      ByVal sender As Object, ByVal e As System.EventArgs)
  Me.Response.Write(txt.Text)
End Sub

To simplify using the control, I declared it as a field at the top of the class. Normally, I'm opposed to using class-level declarations. But the regular controls are, effectively, declared at the class level, so I'm just following this pattern.

And that really does wrap up my exploration adding a control dynamically to page at runtime!

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube