Solved

Handling Events from a Dynamically Added Control

Posted on 2009-04-14
2
334 Views
Last Modified: 2012-05-06
Hello, all!

Handling an event that is raised from a dynamically-added control is a do-able task for me.  What I would like some assistance with is the following:

A user goes to my web application and clicks an "Add Control" button to add a user control to the page.  This control contains a "Change Text" button that I would like to do something when clicked.

The way that I am handing the "Add Control" button is by adding the user control to an array of user controls (stored as a Session variable), and adding all controls in the array to a Panel each time the page is Initialized.  This way I don't lose the controls each postback.

Here's the problem.  When the "Change Text" button is clicked, it re-Initializes (adding the user controls again) and re-Loads the page, without raising the "Change Text" click event.  How can I make this happen?

I've already tried the following:
- Creating a public withevents "Change Text" button in the user control, and using the handles clause to map it to an event handler in the user control's code
- Adding the "Change Text" button when the user control is initialized, and using the AddHandler to map its click event to the correct event handler
- Creating a Public Event in the user control to be raised when the "Change Text" button is clicked, and catching that event on the page side
- Only adding a "Change Text" button, instead of adding a user control that contains a "Change Text" button
- Studying ASP.NET's life cycle to see where things go arye - I think this might be why it's not working, and might not even be possible.

Any and all suggestions are welcome.  Thank you!
0
Comment
Question by:ryankavalsky
2 Comments
 
LVL 29

Expert Comment

by:Kumaraswamy R
ID: 24144548
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:

Declare a button (Button1) in your page markup
Add an event handler for Button1 and in that handler, create a new dynamic button (Button2)
Wire up and event handler for Button2
Page loads an you see Button1
Click on Button1 and the page posts-back Button1's Click event fires and you now see Button1 and Button2
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
----------------
It is important to note that it is not sufficient to re-create the dynamic controls on all subsequent page postbacks.
You need to re-create them with the same ID's (as shown in the code above). The ID's are important for the event mechanism.

If you don't assign ID's, the ASP.NET engine will assign ID's automatically (something like ctl_01, ctl_02, etc.), and sometimes these ID's may be different before and after the postback (for instance if the number of controls has changed in the mean time).

This remark is already stated in the code above, but I think it is important to keep it in mind as a general rule before you start coding dynamic controls.
0
 

Accepted Solution

by:
ryankavalsky earned 0 total points
ID: 24152012
I appreciate the response, but I have already tried this solution as it has been posted here: http://forums.asp.net/p/1408657/3076651.aspx#3076651.  I believe that there is something in the way my classes are inheriting each other (Master Page --> Child Page --> Custom Control --> Sub Custom Control) that is making this more complicated.
Until I find a true solution, I have resolved to hard-code the controls into the page, and simply toggle their visibility after user input.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Today is the age of broadband.  More and more people are going this route determined to experience the web and it’s multitude of services as quickly and painlessly as possible. Coupled with the move to broadband, people are experiencing the web via …
Introduction This article shows how to use the open source plupload control to upload multiple images. The images are resized on the client side before uploading and the upload is done in chunks. Background I had to provide a way for user…
Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).

863 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

22 Experts available now in Live!

Get 1:1 Help Now