1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Why do dynamic controls disappear on postback and not raise events?

Discussion in 'C#' started by rohansyco, Jul 18, 2009.

  1. #1
    One common error that many have run into when first starting out with creating dynamic page controls is an incorrect assumption that those dynamic controls will survive page postbacks.

    For example - a common scenario is to:

    1.
    Declare a button (Button1) in your page markup
    2.
    Add an event handler for Button1 and in that handler, create a new dynamic button (Button2)
    3.
    Wire up and event handler for Button2
    4.
    Page loads an you see Button1
    5.
    Click on Button1 and the page posts-back Button1's Click event fires and you now see Button1 and Button2
    6.
    Click on Button2 and...the page posts-back, Button2 disappears and no event for Button2 is raised.

    What happened to Button2?

    Since Button2 is not part of your pages declared markup, the framework has no way to know if it should be recreated or not on a postback. You'll need to keep track of the fact that you have
    created dynamic control(s) and you will need to add the necessary code to recreate those dynamic control(s) yourself on all subsequent page postbacks. In order for your dynamic control(s)
    to work correctly, you'll need to get them all recreated by the Page_Load event at the latest.

    The following example demonstrates how to toggle between 2 different sets of dynamic controls and how to handle events raised from those controls. In this example, I've chosen ViewState as the place where i will store the information needed to know which dynamic controls need to be recreated on a postback.

    First - here's the basic page markup:

    <form id="form1" runat="server">
    <div>
    <hr />
    <asp:Button ID="cmdAlphabet" runat="server" Text="Load Alphabet" />
    <asp:Button ID="cmdNumbers" runat="server" Text="Load Numbers" />
    <asp:Label ID="lblViewStateValue" runat="server" Text="" EnableViewState="false"></asp:Label>
    <hr />
    <asp:placeHolder ID="PlaceHolder1" runat="server"></asp:placeHolder>
    <hr />
    <asp:Label ID="lblClickResult" runat="server" Text="" EnableViewState="false"></asp:Label>
    </div>
    </form>

    And here's the associated codebehind:

    Partial Class DynamicControls
    Inherits System.Web.UI.Page

    Const ALPHABET_SELECTION As String = "ALPHABET"
    Const NUMBER_SELECTION As String = "NUMBERS"
    Const VIEWSTATEKEY_DYNCONTROL As String = "DynamicControlSelection"

    'store property value in viewstate so that it will survive postbacks
    Private Property DynamicControlSelection() As String
    Get
    Dim result As String = ViewState.Item(VIEWSTATEKEY_DYNCONTROL)
    If result Is Nothing Then
    'doing things like this lets us access this property without
    'worrying about this property returning null/Nothing
    Return String.Empty
    Else
    Return result
    End If
    End Get
    Set(ByVal value As String)
    ViewState.Item(VIEWSTATEKEY_DYNCONTROL) = value
    End Set
    End Property

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load
    'running this code on every page_load - even when it's a postback
    'check our page property (that we stored in viewstate) to see
    'if we need to load a specific set of dynamic controls
    Select Case Me.DynamicControlSelection
    Case ALPHABET_SELECTION
    CreateDynamicAlphabetLinks()

    Case NUMBER_SELECTION
    CreateDynamicNumberButtons()

    Case Else
    'no dynamic controls need to be loaded...yet
    End Select

    End Sub

    Private Sub onClick(ByVal sender As Object, ByVal e As EventArgs)
    'all of the dynamic linkbuttons/buttons will trigger this event handler
    'since we used both linkbuttons and regular buttons for our dynamic controls,
    'we will cast the sender control to an interface that is common to both
    'of those button controls - the IButtonControl interface
    Dim btn As IButtonControl = DirectCast(sender, IButtonControl)
    Me.lblClickResult.Text = _
    String.Format("You clicked - CommandName: {0} CommandArgument: {1}", _
    btn.CommandName, btn.CommandArgument)
    End Sub

    Protected Sub cmdAlphabet_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdAlphabet.Click
    'user is selecting to show the dynamic Alphabet buttons
    Me.CreateDynamicAlphabetLinks()
    End Sub

    Protected Sub cmdNumbers_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdNumbers.Click
    'user is selecting to show the dynamic Number buttons
    Me.CreateDynamicNumberButtons()
    End Sub

    Private Sub CreateDynamicAlphabetLinks()

    'clear the placeholder first - in case something else was dynamically loaded
    Me.PlaceHolder1.Controls.Clear()

    'dynamically create a series of linkbuttons
    For keycode As Integer = 65 To 90 'one for each letter in the alphabet
    Dim lnk As New LinkButton

    'assign the ID ourself to make sure it is consistent
    'if you let the framework assign it, the dynamic control may
    'not behave correctly
    lnk.ID = "alpha_" & keycode.ToString
    lnk.Text = Chr(keycode)

    'we'll add a CommandName and a CommandArgument
    'so we can determine what was clicked when the event is raised
    lnk.CommandName = "ALPHABET"
    lnk.CommandArgument = Chr(keycode)

    'have them all use the same event handler
    AddHandler lnk.Click, AddressOf onClick

    'add these dynamic controls to our strategically place placeholder control
    'the position of the placeholder determines
    'where on the page the dynamic controls will appear
    Me.PlaceHolder1.Controls.Add(lnk)
    Me.PlaceHolder1.Controls.Add(New LiteralControl(" ")) 'space them out
    Next

    'VERY IMPORTANT -> remember that we created these controls for the next postback
    Me.DynamicControlSelection = ALPHABET_SELECTION

    End Sub

    Private Sub CreateDynamicNumberButtons()

    'clear the placeholder first - in case something else was dynamically loaded
    Me.PlaceHolder1.Controls.Clear()

    'dynamically create a series of button controls
    For number As Integer = 0 To 25
    Dim btn As New Button
    'assign the ID ourself to make sure it is consistent
    'if you let the framework assign it, the dynamic control may
    'not behave correctly
    btn.ID = "number_" & number.ToString
    btn.Text = number.ToString

    'we'll add a CommandName and a CommandArgument
    'so we can determine what was clicked when the event is raised
    btn.CommandName = "NUMBER"
    btn.CommandArgument = number.ToString

    'have them all use the same event handler
    AddHandler btn.Click, AddressOf onClick

    'add these dynamic controls to our strategically place placeholder control
    'the position of the placeholder determines
    'where on the page the dynamic controls will appear
    Me.PlaceHolder1.Controls.Add(btn)
    Me.PlaceHolder1.Controls.Add(New LiteralControl(" ")) 'space them out
    Next

    'VERY IMPORTANT -> remember that we created these controls for the next postback
    Me.DynamicControlSelection = NUMBER_SELECTION

    End Sub

    Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.PreRender
    Me.lblViewStateValue.Text = Me.DynamicControlSelection
    End Sub
    End Class
     
    rohansyco, Jul 18, 2009 IP