Solved

controls disappearing from placeholder on postback

Posted on 2003-10-24
14
1,975 Views
Last Modified: 2007-12-19
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
0
Comment
Question by:Gezna
14 Comments
 
LVL 12

Expert Comment

by:roverm
Comment Utility
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
        plhmenu.Controls.Add(bt)

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
        Try
            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!

D'Mzz!
RoverM
0
 
LVL 28

Assisted Solution

by:iboutchkine
iboutchkine earned 100 total points
Comment Utility
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.

So:

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
 Get
   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")
 pnlControlHolder.Controls.Add(mySecurityControl)
 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
    CreateControl(ControlCount)
    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
         CreateControl(intIndex)
       Next
     End If
  End Sub





0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
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.

0
 

Author Comment

by:Gezna
Comment Utility
roverm,

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?
0
 
LVL 23

Expert Comment

by:naveenkohli
Comment Utility
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,
0
 
LVL 12

Accepted Solution

by:
roverm earned 400 total points
Comment Utility
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">
<HTML>
      <HEAD>
            <title>test</title>
            <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="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
      <script language="javascript">
            function fakeit()
            { var x=fakeit.arguments[0];
              document.all.thevalue.value=x.value;
              __doPostBack('bt','');
              return false;
            }
      </script>
      </HEAD>
      <body>
            <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>
      </body>
</HTML>

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.
        InitializeComponent()
    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);")
        plh.Controls.Add(cb)
    End Sub

    Private Sub bt_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bt.Click
        Response.Write(Request("thevalue"))
    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.

D'Mzz!
RoverM
0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
btw: You can leave the 'AutoPostBack = True' out.
There's no need for that.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:Gezna
Comment Utility
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);")
        plh.Controls.Add(cb)

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);")
        plh.Controls.Add(cb2)
    End Sub

    Private Sub bt_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles bt.Click
        Response.Write(Request("thevalue"))

'NEED TO GET THE SELECTED VALUE OF DEPARTMENT LIST
Dim selDept As String

selDept = Request.form("cb")

'USING selDept NEED TO UPDATE THE ACCOUNT LIST
'SOMETHING LIKE...

plh.controls.findcontrol("cb2").items.add("Account 4")
'HOWEVER THIS DOESN'T WORK BECAUSE plh.hascontrols RETURNS FALSE AFTER POSTBACK AND IF I DO THE ABOVE LINE I GET AN ERROR

    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

Thanks,

Gezna
0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
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.

D'Mzz!
RoverM
0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
Gezna, any progress?
0
 

Author Comment

by:Gezna
Comment Utility
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
                plcCodeLines.Controls.Add(Ctrl)
            Next
if not ispostback then
Try
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
                                   Else
                                    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

                                      sessColl.Add(ctrl)
                                      plcCodeLines.Controls.Add(ctrl)
                                index2 = index2 + 1
                                Next
                                combocount = combocount + 1
                           Next
        Catch ex As Exception
            Response.Write(ex)
        End Try
     
     End if
    End Sub

It works great, but you guys really helped me figure out what was going on.
0
 

Author Comment

by:Gezna
Comment Utility
Hope I didn't step on any toes, I'm new to the Experts-Exchange world
0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
Great, then please close the question so it will go to the PAQ database.

Just remember that Session state 'eats' your server memory!
0
 
LVL 12

Expert Comment

by:roverm
Comment Utility
Ok, that for closing and the points!
Glad we could help you and welcome to EE!!
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Normally the drop down box control found in the .Net framework tools is able to select just one data and value at a time, which is displayed on the text area.   But what if you want to have multiple values to be selected in the drop down box? As …
The object model of .Net can be overwhelming at times – so overwhelming that quite trivial tasks often take hours of research. In this case, the task at hand was to populate the datagrid from SQL Server database in Visual Studio 2008 Windows applica…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now