controls disappearing from placeholder on postback

I have  a page upon which I have to add controls at runtime. They are rows of textboxes and dropdownlists, which I name ctrl00...ctrl09 and ctrl10...ctrl19 per row where the first digit is the row and the seecond is the column.

I have used a two dimensional array to initailize the controls to textboxes or dropdownlists, but then I add the control to a placeholder, like this:

 plcCodeLines.Controls.Add(CType(codeLine(index2), System.web.ui.Control))

However I need the user to be able to select from a dropdown list and when they do this another dropdown list is repopulated.

for example accounts are linked to departments, so when a user selects a certain department in a row I want the account dropdown list in the same row to populate with the department specific accounts. I have set these controls postback property to true.

However I can't seem to get a hold of the controls to update them after the postback.

The place holder returns false for  Response.Write(plcCodeLines.HasControls) on the postback.

I can get a hold of the selected values by using request.form("ctrl00")

What is going on?? When I use the trace, I can see the controls in the control tree and the in the form collection (after postback)

Anything to do with viewstate?? This is a server-side web app by the way
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I did this a little different:

Instead of adding the controls as you did, I created the control like this:

        Dim bt As New LinkButton
        With bt
            .Text = strName
            .ID = strID
            .CommandName = strName
            .Enabled = blnEnabled
        End With
        AddHandler bt.Click, AddressOf HandleEvent

As you can see I added a handler to catch the linkbutton's event.
The event is handled in 'HandleEvent' :

    Private Sub HandleEvent(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim strCommand As String
            strCommand = sender.CommandName
        Catch ex As Exception

        End Try
        'do some additional coding
    End Sub

Of course you can do the same for other controls.

If you need more information please let me know!

When you create controls dynamically they will disappear on every postback!!!!!!
Dynamically added controls need to be re-added on each Postback.

When you are creating dynamic controls in a container, you have to recreate each control with every
postback. It seems weird, I know, because after you recreate the dynamic control it's propertires and
values will still be restored by viewstate. You just have to alert your page that these controls still exist
since you are not doing it declaratively.


Add this Property:

'This property will keep track of how many control we have on the page
Private Property ControlCount() As Integer
 Set(ByVal Value As Integer)
   ViewState("ControlCount") = Value
 End Set
   If ViewState("ControlCount") Is Nothing Then
     ViewState("ControlCount") = 0
   End If
   Return ViewState("ControlCount")
 End Get
End Property

Add this sub:

'This sub will call laodcontrol and add the control to the page
Private Sub CreateControl(ByVal intIndex As Integer)
 Dim mySecurityControl As SetSecurityForSystem = LoadControl("SetSecurityForSystem.ascx")
 mySecurityControl.ID = "mySecurityControl" & intIndex
End Sub

Change your click event handler to this:

  'Add a new control and increment our counter when the button is clicked
  Private Sub cmdSetSystemSecurity_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetSystemSecurity.Click
    ControlCount += 1
  End Sub

Change your Page_Load to this:

  'If the page is posted back, check our counter and re add teh appropriate number of controls
  Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
     Dim intIndex As Integer = 0
     If Page.IsPostback()
       For intIndex = 0 To ControlCount - 1
     End If
  End Sub

iboutchkine is correct, all controls will disappear on a postback.

That's why I've build a seperate WebUserControl which builds the controls for me.
In that WCC the controls are created on each page_load.

Become a CompTIA Certified Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

GeznaAuthor Commented:

That is almost exactly what I am looking for, except the control (a dropdownlist) that triggers the handler when it's selected index has changed, has to update a control (also a dropdown list) based on its selected item.

The dropdown list that has to be updated is also a dynamic control that I can't "get a hold of"

Any more ideas?
Did you add the other dropdown list into the page's control tree before the selected dropdown liist's event handler is invoked. If you haven't done that, you are not going to find it in the event handler. Bottom line is that in Page_Load, reconstruct the controls that were there before post back was fired only then the framework will reinstate the control values from view state,
Hi Gezna,

Ok, build you an example.
The problem is that you can't assign to onchange event and capture that serverside.
However, I faked the postback and now it works.

You need to add a dummy linkbutton to the page, called 'bt'. Just don't set the text (even empty it) so that you won't see it.

Then add a normal input, type hidden. Call it 'thevalue'.
We are going to use this a dummy for retrieving the selected value.

So, this will give you this page (I called it test.aspx):

<%@ Page Language="vb" AutoEventWireup="false" Codebehind="test.aspx.vb" Inherits="VIMWebmailing.test"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
            <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
            <meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
            <meta content="JavaScript" name="vs_defaultClientScript">
            <meta content="" name="vs_targetSchema">
      <script language="javascript">
            function fakeit()
            { var x=fakeit.arguments[0];
              return false;
            <form id="Form1" method="post" runat="server">
                  <asp:placeholder id="plh" runat="server"></asp:placeholder><input name="thevalue" type="hidden">
                  <asp:LinkButton id="bt" runat="server"></asp:LinkButton></form>

As you can see, there's also a javascript function which fills the dummy and fakes the postback.

This is the vb page:
Public Class test
    Inherits System.Web.UI.Page

#Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents plh As System.Web.UI.WebControls.PlaceHolder
    Protected WithEvents bt As System.Web.UI.WebControls.LinkButton

    'NOTE: The following placeholder declaration is required by the Web Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
    End Sub

#End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim cb As New DropDownList
        With cb
            .Items.Add("this is item 1")
            .Items.Add("and this is item 2")
            .Items.Add("and finally item 3")
            .AutoPostBack = True
        End With
        cb.Attributes.Add("onchange", "javascript:return fakeit(this);")
    End Sub

    Private Sub bt_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bt.Click
    End Sub
End Class

As you can see the bt_Click event will handle the change of the dropdownlist.

Of course you can use this function to handle all dropdownlists on your form. Just add another hidden input and store the senders name in that.

If you need to know more just let me know.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
btw: You can leave the 'AutoPostBack = True' out.
There's no need for that.
GeznaAuthor Commented:
Hi roverm,

I've modified your page_load a bit to see if you can show me how I would do what I need to do cause it's still a bit unclear to me.

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim cb As New DropDownList
        With cb
            .Items.Add("Department 1")
            .Items.Add("Department 2")
            .Items.Add("Department 3")
            .AutoPostBack = True
        End With
        cb.Attributes.Add("onchange", "javascript:return fakeit(this);")

Dim cb2 As New DropDownList
        With cb2
            .Items.Add("Account 1")
            .Items.Add("Account 2")
            .Items.Add("Account 3")
            .AutoPostBack = True
        End With
cb2.Attributes.Add("onchange", "javascript:return fakeit(this);")
    End Sub

    Private Sub bt_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bt.Click

Dim selDept As String

selDept = Request.form("cb")


plh.controls.findcontrol("cb2").items.add("Account 4")

    End Sub
End Class

Your first code snippet with the handler almost worked for me except I could only manipulate the control which caused the postback (the sender) and not the second control whose list depends on what value was selected for the sender

Perhaps I'm being a bit dense here, but I'm new to ASP.Net and some of the concepts haven't sunk in yet


Hi Gezna,

The problem is that in a postback the dropdownlists are gone.
So instead of adding an item to the collection you need to recreate the controls on every postback.

Since your data seems to come from a database that shouldn't be a problem.

Gezna, any progress?
GeznaAuthor Commented:
I've just figured out a  way to do it which is best for me to recreate the controls at postback. A collegue has suggested that I try creating a controls collection on the session level and use it to add my controls the first time and then on every postback reload the control from the collection to the placeholder.

'Here is where the controls collection is declared
Public Class Global
    Inherits System.Web.HttpApplication
      Public Shared sessColl As ControlCollection

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when the session is started
        Dim owner As System.Web.UI.Control = New System.Web.UI.Control
        sessColl = New ControlCollection(owner)

    End Sub
End Class

'Here is the page load on the page that has the dynamic controls
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

If IsPostBack Then
            Dim ctrl As System.Web.UI.Control
            For Each ctrl In sessColl
if not ispostback then
Dim combocount, index2 As integer
                    For comboCount = 0 To BSSds.Tables("combobox").Rows.Count - 1
                          For index2 = 0 To 11
                                   Dim ctrl As Object
                                   If index2 = 0 Or index2 > 7 Then
                                    ctrl = New System.Web.UI.WebControls.TextBox
                                    ctrl = New System.Web.UI.WebControls.DropDownList
                                   End If
                    ctrl.ID = "ctrl" & comboCount & index2
                    If index2 = 1 Or index2 = 3 Or index2 = 8 Or index2 = 9 Then                         ctrl.autopostback = True
                    End If

'Adds the line of coding to the place holder and update the debit and credit totals

                                index2 = index2 + 1
                                combocount = combocount + 1
        Catch ex As Exception
        End Try
     End if
    End Sub

It works great, but you guys really helped me figure out what was going on.
GeznaAuthor Commented:
Hope I didn't step on any toes, I'm new to the Experts-Exchange world
Great, then please close the question so it will go to the PAQ database.

Just remember that Session state 'eats' your server memory!
Ok, that for closing and the points!
Glad we could help you and welcome to EE!!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.