Trouble with dynamically added controls

Discussion in 'ASP .Net Building Controls' started by Daniel Walzenbach, Oct 15, 2003.

  1. Hi everybody,

    I need to dynamically populate a webpage at runtime with controls. This is the code I wrote.



    Public Class WebForm1

    Inherits System.Web.UI.Page



    #Region " Vom Web Form Designer generierter Code "



    'Dieser Aufruf ist für den Web Form-Designer erforderlich.

    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()



    End Sub

    Protected WithEvents PlaceHolder1 As System.Web.UI.WebControls.PlaceHolder

    Protected WithEvents Button1 As System.Web.UI.WebControls.Button



    'HINWEIS: Die folgende Platzhalterdeklaration ist für den Web Form-Designer erforderlich.

    'Nicht löschen oder verschieben.

    Private designerPlaceholderDeclaration As System.Object



    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init

    'CODEGEN: Dieser Methodenaufruf ist für den Web Form-Designer erforderlich

    'Verwenden Sie nicht den Code-Editor zur Bearbeitung.

    InitializeComponent()

    End Sub



    #End Region



    Private counter As System.Int32 = 0



    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    ' Hier Benutzercode zur Seiteninitialisierung einfügen

    End Sub



    Private Sub AddControls(ByVal strLabel As String)



    Dim myNewLabel As New System.Web.UI.WebControls.Label



    ' counter to give objects different names

    counter = Session.Item("Counter")

    counter += 1

    Session.Item("counter") = counter



    myNewLabel.ID = String.Format("myNewLabel{0}", counter)

    myNewLabel.Text = strLabel & CStr(counter)

    ' I thought that EnableViewState should be sufficient to store the controls value

    myNewLabel.EnableViewState = True





    ' save controls for ViewState

    Dim dynControls As System.Collections.ArrayList

    dynControls = Viewstate.Item("dynControls")



    ' create new ArrayList if it does not exist

    If dynControls Is Nothing Then

    dynControls = New System.Collections.ArrayList

    End If



    'store information about control in Triplet

    Dim labelTrip As New System.Web.UI.Triplet

    labelTrip.First = myNewLabel.ID

    labelTrip.Second = myNewLabel.GetType.ToString

    labelTrip.Third = PlaceHolder1.ID

    dynControls.Add(labelTrip)





    ' put control on Placeholder

    PlaceHolder1.Controls.Add(myNewLabel)

    ' and save information about control in ViewState

    ViewState("dynControls") = dynControls





    End Sub



    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    AddControls("Created From Button")



    End Sub



    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)



    Dim SampleAssembly As System.Reflection.Assembly




    Dim t As Type

    t = GetType(System.Web.UI.WebControls.Label)



    SampleAssembly = System.Reflection.Assembly.Load(t.Assembly.FullName)



    Dim dynControls As System.Collections.ArrayList

    dynControls = ViewState.Item("dynControls")



    If Not dynControls Is Nothing Then



    ' run through all saved controls

    For Each obj As System.Object In dynControls

    Dim ctlTrip As System.Web.UI.Triplet

    ctlTrip = CType(obj, System.Web.UI.Triplet)



    Dim parent As System.Web.UI.WebControls.PlaceHolder

    parent = Page.FindControl(ctlTrip.Third)



    Dim ctl As System.Web.UI.Control

    Try

    'ctl = Activator.CreateInstance(Type.GetType(ctlTrip.Second, True))

    ctl = Activator.CreateInstance(SampleAssembly.GetType(ctlTrip.Second, True))



    Catch ex As Exception

    Response.Write(ex.Message)

    End Try

    ctl.ID = ctlTrip.First



    parent.Controls.Add(ctl)

    Next



    End If



    End Sub



    End Class



    The controls get recreated in the OnLoad method but don't contain any values. I thought their values should be stored in ViewState? Does anybody know why the controls don't contain any values?



    Thanks in advance

    Best regards


    Daniel Walzenbach

    P.S. If you need to contact me simply remove ".NOSPAM" from my email address.
    Daniel Walzenbach, Oct 15, 2003
    #1
    1. Advertising

  2. Hi Daniel,

    Based on my research and experience, I would like to share the following
    information with you.

    At the OnLoad stage in the page lifecycle, server controls in the hierarchy
    are created and initialized, view state is restored. That is, any control
    created in OnLoad phrase has no chance to get its viewstate back.

    Please override the OnInit method and move the creation of the controls to
    this stage, for in this stage of the server control's lifecycle, the
    control's view state has yet to be populated.

    I hope it helps.

    Best regards,

    Jacob Yang
    Microsoft Online Partner Support
    Get Secure! ¨C www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
    Jacob Yang [MSFT], Oct 16, 2003
    #2
    1. Advertising

  3. Daniel Walzenbach

    Teemu Keiski Guest

    Hi,

    I'd like to say a few words.

    First: control lifecycle is as follows:

    1. Instantiate
    2. Initialize
    3. TrackViewState
    4. LoadViewState (postback)
    5. Load postback data (postback, IPostBackDatahandler.LoadPostdata)
    6. Load
    7. Load postback data for dynamical controls added on Page_Load
    8. Raise Changed Events (postback,
    IPostBackDatahandler.RaisePostDataChanged)
    9. Raise postback event (postback, IPostBackEventHandler.RaisePostBackEvent)
    10.PreRender
    11. SaveViewState
    12. Render
    13. Unload
    14. Dispose

    Second, dynamically added control *can* load its ViewState after
    LoadViewState phase. This happens "automagically" when control just is added
    to the Control tree and as it is dynamical control it needs to be added on
    every request. Adding control to the control tree in the same order
    (position) is important because ViewState mechanism relies on control's
    index in Controls collection, not for example on Controläs ID. This is for
    performance reasons.

    Another thing is that controls that load postback data needs to be added to
    the control tree at Loads phase at ther latest during the request they do
    postback data processing. That's because postback data loading is intiated
    by the Page itself. With ViewState loading (when control is added), it is
    the ControlCollection that handles the plumbing and therefore control can
    load ViewState during the lifecycle.

    More complete explanation and for simple example see:
    http://www.asp.net/Forums/ShowPost.aspx?tabindex=1&PostID=250529

    Thanks,
    --
    Teemu Keiski
    MCP, Microsoft MVP (ASP.NET), AspInsiders member
    ASP.NET Forum Moderator, AspAlliance Columnist

    "Jacob Yang [MSFT]" <> wrote in message
    news:...
    > Hi Daniel,
    >
    > Based on my research and experience, I would like to share the following
    > information with you.
    >
    > At the OnLoad stage in the page lifecycle, server controls in the

    hierarchy
    > are created and initialized, view state is restored. That is, any control
    > created in OnLoad phrase has no chance to get its viewstate back.
    >
    > Please override the OnInit method and move the creation of the controls to
    > this stage, for in this stage of the server control's lifecycle, the
    > control's view state has yet to be populated.
    >
    > I hope it helps.
    >
    > Best regards,
    >
    > Jacob Yang
    > Microsoft Online Partner Support
    > Get Secure! ¨C www.microsoft.com/security
    > This posting is provided "as is" with no warranties and confers no rights.
    >
    Teemu Keiski, Oct 16, 2003
    #3
  4. Hi Daniel,

    Firstly I want to thank Teemu's great help on this issue. Please refer to
    his response carefully.

    From your code snippet, I am not sure how you assign the values to those
    dynamical controls.

    The postback data processing and the viewstate restore were done
    automatically by page in each request.

    One important thing is that those dynamical controls should be added to the
    control tree in the same order in each request, including the first
    request. Otherwise, the viewstate will fail to work.

    Please try the following code, checking whether it works fine,

    1. Create a new ASP.NET (VB.NET) app,
    2. Webform1.aspx will be added be default.
    3. Drap and drop a button onto the web from.
    4. Copy the following code into the Page_Load event.

    'Put user code to initialize the page here
    Dim l As Label = New Label
    Page.Controls(1).Controls.Add(l)

    Dim txt As TextBox = New TextBox
    Page.Controls(1).Controls.Add(txt)

    If (Not IsPostBack) Then
    l.Text = "Set on initial request"
    End If

    5. Compile and browse the webform1.aspx.
    6. Type any chars into the textbox that was added dynamically.
    7. Click the button to submit the webform. When the submit completed, you
    should see the value you typed in the textbox should persist, and also the
    text of the Label control should also be there.

    Please try it and let me know the result.

    Best regards,

    Jacob Yang
    Microsoft Online Partner Support
    Get Secure! ¨C www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
    Jacob Yang [MSFT], Oct 17, 2003
    #4
  5. Hi Jacob,



    Well, your example worked perfectly well which makes it more wired form e as
    I thought I made exactly the same thing. I mean there must be a difference
    otherwise it would work but I can't see it. As it is late by now I'll look
    over it tomorrow in a more pronounced way.



    Thank you for your help! The code you gave me is a good basis for a start
    :) At least I know by now what does work.



    Daniel





    "Jacob Yang [MSFT]" <> schrieb im Newsbeitrag
    news:...
    > Hi Daniel,
    >
    > Firstly I want to thank Teemu's great help on this issue. Please refer to
    > his response carefully.
    >
    > From your code snippet, I am not sure how you assign the values to those
    > dynamical controls.
    >
    > The postback data processing and the viewstate restore were done
    > automatically by page in each request.
    >
    > One important thing is that those dynamical controls should be added to

    the
    > control tree in the same order in each request, including the first
    > request. Otherwise, the viewstate will fail to work.
    >
    > Please try the following code, checking whether it works fine,
    >
    > 1. Create a new ASP.NET (VB.NET) app,
    > 2. Webform1.aspx will be added be default.
    > 3. Drap and drop a button onto the web from.
    > 4. Copy the following code into the Page_Load event.
    >
    > 'Put user code to initialize the page here
    > Dim l As Label = New Label
    > Page.Controls(1).Controls.Add(l)
    >
    > Dim txt As TextBox = New TextBox
    > Page.Controls(1).Controls.Add(txt)
    >
    > If (Not IsPostBack) Then
    > l.Text = "Set on initial request"
    > End If
    >
    > 5. Compile and browse the webform1.aspx.
    > 6. Type any chars into the textbox that was added dynamically.
    > 7. Click the button to submit the webform. When the submit completed, you
    > should see the value you typed in the textbox should persist, and also the
    > text of the Label control should also be there.
    >
    > Please try it and let me know the result.
    >
    > Best regards,
    >
    > Jacob Yang
    > Microsoft Online Partner Support
    > Get Secure! ¨C www.microsoft.com/security
    > This posting is provided "as is" with no warranties and confers no rights.
    >
    Daniel Walzenbach, Oct 18, 2003
    #5
  6. Well. I finally got it to work. Thanks to everybody who helped me. If you
    are interested how to dynamically create controls on a website on click and
    preserve their ViewState here your go:



    Your aspx site should look something like this:



    <%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb"
    Inherits="DynamicControlsAdd.WebForm1" trace = true %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

    <HTML>

    <HEAD>

    <title>WebForm1</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">

    </HEAD>

    <body>

    <form id="Form1" method="post" runat="server">

    <asp:placeholder id="myPlaceHolder"
    runat="server"></asp:placeholder><BR>

    <BR>

    <BR>

    <asp:button id="btnAddTextBox" runat="server" Text="Add
    Textbox"></asp:button>

    </form>

    </body>

    </HTML>



    And here is the code behind:



    Public Class WebForm1

    Inherits System.Web.UI.Page



    #Region " Vom Web Form Designer generierter Code "



    'Dieser Aufruf ist für den Web Form-Designer erforderlich.

    <System.Diagnostics.DebuggerStepThrough()> Private Sub
    InitializeComponent()



    End Sub

    Protected WithEvents myPlaceHolder As
    System.Web.UI.WebControls.PlaceHolder

    Protected WithEvents btnAddTextBox As System.Web.UI.WebControls.Button



    'HINWEIS: Die folgende Platzhalterdeklaration ist für den Web
    Form-Designer erforderlich.

    'Nicht löschen oder verschieben.

    Private designerPlaceholderDeclaration As System.Object



    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
    System.EventArgs) Handles MyBase.Init

    'CODEGEN: Dieser Methodenaufruf ist für den Web Form-Designer
    erforderlich

    'Verwenden Sie nicht den Code-Editor zur Bearbeitung.

    InitializeComponent()

    End Sub



    #End Region



    Private counter As System.Int32 = 0



    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
    System.EventArgs) Handles MyBase.Load

    ' Hier Benutzercode zur Seiteninitialisierung einfügen

    InitPage()

    End Sub



    Private Sub AddControls(ByVal strLabel As String)



    Dim myNewTextBox As New System.Web.UI.WebControls.TextBox



    ' counter to give objects different names

    counter = Session.Item("Counter")

    counter += 1

    Session.Item("counter") = counter



    myNewTextBox.ID = String.Format("myNewTextBox{0}", counter)

    myNewTextBox.Text = strLabel & CStr(counter)

    myNewTextBox.EnableViewState = True





    ' save controls for SessionState

    Dim dynControls As System.Collections.ArrayList

    dynControls = Session.Item("dynControls")



    ' create new ArrayList if it does not exist

    If dynControls Is Nothing Then

    dynControls = New System.Collections.ArrayList

    End If



    'store information about control in Triplet

    Dim ControlTrip As New System.Web.UI.Triplet

    ControlTrip.First = myNewTextBox.ID

    ControlTrip.Second = myNewTextBox.GetType.ToString

    ControlTrip.Third = myPlaceHolder.ID

    dynControls.Add(ControlTrip)





    ' put control on Placeholder

    myPlaceHolder.Controls.Add(myNewTextBox)

    ' and save information about control in SessionState

    Session.Item("dynControls") = dynControls



    End Sub



    Private Sub btnAddTextBox_Click(ByVal sender As System.Object, ByVal e
    As System.EventArgs) Handles btnAddTextBox.Click

    AddControls("Created From Button")



    End Sub



    Private Sub InitPage()

    Dim SampleAssembly As System.Reflection.Assembly



    ' Load the assembly by providing the type name. Needs to be done
    to instanciate the control

    ' with "CreateInstance" which needs a fully qualified name

    Dim t As Type

    t = GetType(System.Web.UI.WebControls.Label)



    SampleAssembly =
    System.Reflection.Assembly.Load(t.Assembly.FullName)



    Dim dynControls As System.Collections.ArrayList

    dynControls = Session.Item("dynControls")



    If Not dynControls Is Nothing Then



    Dim myEnumerator As IEnumerator

    myEnumerator = dynControls.GetEnumerator



    ' run through all saved controls

    While myEnumerator.MoveNext

    Dim ctlTrip As System.Web.UI.Triplet



    ' restore Triplet containing informations about the
    control

    ctlTrip = CType(myEnumerator.Current,
    System.Web.UI.Triplet)



    Dim myPlaceHolder As
    System.Web.UI.WebControls.PlaceHolder

    myPlaceHolder = Page.FindControl(ctlTrip.Third)



    Dim ctl As System.Web.UI.Control

    Try

    ctl =
    Activator.CreateInstance(SampleAssembly.GetType(ctlTrip.Second, True))

    ctl.ID = ctlTrip.First



    Catch ex As Exception

    Response.Write(ex.Message)

    End Try



    myPlaceHolder.Controls.Add(ctl)



    End While



    End If

    End Sub



    End Class



    Thank you again Jacob and Teemu for your help!

    Best regards


    Daniel Walzenbach

    P.S. If you need to contact me simply remove ".NOSPAM" from my email address



    "Daniel Walzenbach" <> schrieb im
    Newsbeitrag news:...
    > Hi Jacob,
    >
    >
    >
    > Well, your example worked perfectly well which makes it more wired form e

    as
    > I thought I made exactly the same thing. I mean there must be a difference
    > otherwise it would work but I can't see it. As it is late by now I'll look
    > over it tomorrow in a more pronounced way.
    >
    >
    >
    > Thank you for your help! The code you gave me is a good basis for a start
    > :) At least I know by now what does work.
    >
    >
    >
    > Daniel
    >
    >
    >
    >
    >
    > "Jacob Yang [MSFT]" <> schrieb im Newsbeitrag
    > news:...
    > > Hi Daniel,
    > >
    > > Firstly I want to thank Teemu's great help on this issue. Please refer

    to
    > > his response carefully.
    > >
    > > From your code snippet, I am not sure how you assign the values to those
    > > dynamical controls.
    > >
    > > The postback data processing and the viewstate restore were done
    > > automatically by page in each request.
    > >
    > > One important thing is that those dynamical controls should be added to

    > the
    > > control tree in the same order in each request, including the first
    > > request. Otherwise, the viewstate will fail to work.
    > >
    > > Please try the following code, checking whether it works fine,
    > >
    > > 1. Create a new ASP.NET (VB.NET) app,
    > > 2. Webform1.aspx will be added be default.
    > > 3. Drap and drop a button onto the web from.
    > > 4. Copy the following code into the Page_Load event.
    > >
    > > 'Put user code to initialize the page here
    > > Dim l As Label = New Label
    > > Page.Controls(1).Controls.Add(l)
    > >
    > > Dim txt As TextBox = New TextBox
    > > Page.Controls(1).Controls.Add(txt)
    > >
    > > If (Not IsPostBack) Then
    > > l.Text = "Set on initial request"
    > > End If
    > >
    > > 5. Compile and browse the webform1.aspx.
    > > 6. Type any chars into the textbox that was added dynamically.
    > > 7. Click the button to submit the webform. When the submit completed,

    you
    > > should see the value you typed in the textbox should persist, and also

    the
    > > text of the Label control should also be there.
    > >
    > > Please try it and let me know the result.
    > >
    > > Best regards,
    > >
    > > Jacob Yang
    > > Microsoft Online Partner Support
    > > Get Secure! ¨C www.microsoft.com/security
    > > This posting is provided "as is" with no warranties and confers no

    rights.
    > >

    >
    >
    Daniel Walzenbach, Oct 19, 2003
    #6
  7. Hi Daniel,

    Congratulations!

    I am very glad to know that the problem is resolved. Thank you for sharing
    your resolution. It is helpful to everybody here.

    Best regards,

    Jacob Yang
    Microsoft Online Partner Support
    Get Secure! ¨C www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
    Jacob Yang [MSFT], Oct 20, 2003
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Harry
    Replies:
    1
    Views:
    1,668
    Natty Gur
    Jun 25, 2003
  2. NotYetaNurd
    Replies:
    1
    Views:
    459
    John Saunders
    Nov 7, 2003
  3. Jeffrey Todd
    Replies:
    1
    Views:
    4,101
    Peter Blum
    Jun 2, 2005
  4. David Hubbard
    Replies:
    2
    Views:
    624
    David Hubbard
    Jan 17, 2006
  5. ENathan

    existing controls overlaying dynamically added controls

    ENathan, Jan 10, 2005, in forum: ASP .Net Web Controls
    Replies:
    2
    Views:
    196
    Steve C. Orr [MVP, MCSD]
    Jan 10, 2005
Loading...

Share This Page