Solved

Handling Events from a Dynamically Added Control

Posted on 2009-04-14
2
332 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
Comment Utility
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
Comment Utility
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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

In .NET 2.0, Microsoft introduced the Web Site.  This was the default way to create a web Project in Visual Studio 2005.  In Visual Studio 2008, the Web Application has been restored as the default web Project in Visual Studio/.NET 3.x The Web Si…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

743 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

17 Experts available now in Live!

Get 1:1 Help Now