[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
?
Solved

Handling postback with dynamically created buttons

Posted on 2006-11-08
11
Medium Priority
?
670 Views
Last Modified: 2008-02-01
Hi,

I am creating an array of buttons and inserting them into a table. trouble is the event handling for the buttons doesnt occur after post back unless I re-create the buttons in the onload event of the code behind.

As after post back I want to re-create the buttons with different render options (I neeed to insert extra cells into a dynamic table depending on the button pressed) but with the same CommandNames as the original render I run into problems as I am effectivly creating the buttons twice. i.e the first buttonarray I create on page load has 10 buttons with commandnames going from 1-10 after post back, in order to gain access to the command name I need to create the buttons again (1-10), when I create the new array of buttons it gives the commandName 11-20.

How do I either preserve the button array through postback (viewstate doesnt seem to work) or access the button handle without re-creating the buttons?  Code Below:


Partial Class shop_components_BrowseBar
    Inherits System.Web.UI.UserControl
    Dim ButtonArray(0) As LinkButton
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load


        '### select cetagories on e at a time and them

        Dim CatReader As MySqlDataReader = CreateReader("SELECT * FROM Categories")

        '# set options for the table
        CategoryTbl.BorderStyle = BorderStyle.None
        CategoryTbl.BorderColor = Drawing.Color.Transparent
        CategoryTbl.BorderWidth = 0

        Do While CatReader.Read '# loop through categores
            '#Add category to table
            AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
            'resize the button array
            ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
        Loop

    End Sub


    Sub AddCat(ByVal CellText As String, ByVal CellColour As Drawing.Color, ByVal ID As String)
        Dim objRow As TableRow = New TableRow
        Dim objCell As New TableCell

        ButtonArray(UBound(ButtonArray)) = New LinkButton

        With ButtonArray(UBound(ButtonArray))
            .Text = CellText
            .CommandName = ID
            AddHandler .Click, AddressOf ButtonHandler
        End With

        objCell.Controls.Add(ButtonArray(UBound(ButtonArray)))   '.Text = "<a href='" & HyperLink & "'>" & CellText & "</a>"
        objRow.BorderColor = Drawing.Color.Transparent
        objRow.Cells.Add(objCell)
        objRow.BackColor = CellColour
        objRow.Font.Size = "10"

        CategoryTbl.Rows.Add(objRow)
    End Sub

    Sub AddRow(ByVal CellText As String, ByVal CellColour As Drawing.Color, ByVal HyperLink As String)

        Dim objRow As TableRow = New TableRow
        Dim objCell As New TableCell
        If HyperLink = "" Then
            objCell.Text = CellText
        Else
            objCell.Text = "<a href='" & HyperLink & "'>" & CellText & "</a>"
        End If
        objRow.BorderColor = Drawing.Color.Transparent
        objRow.Cells.Add(objCell)
        objRow.BackColor = CellColour
        objRow.Font.Size = "10"

        CategoryTbl.Rows.Add(objRow)
    End Sub


    Public Sub ButtonHandler(ByVal sender As System.Object, ByVal e As System.EventArgs)
        '# destroy the button array
        ReDim ButtonArray(0)
        '# get the cat ID of the button
        Dim PrimeCatID As Integer = CType(sender, LinkButton).CommandName
        '#  destroy the html from the original table so we can build it again
        CategoryTbl.Rows.Clear()
        ' get th ebutton id and populate the sub categories
        Dim SubCatReader As MySqlDataReader = CreateReader("SELECT * FROM subcategories WHERE CatID = " & PrimeCatID)

        Dim CatReader As MySqlDataReader = CreateReader("SELECT * FROM Categories")

        Do While CatReader.Read '# loop through categores
            '#Add category to table
            AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
            '# see if is needs children and if so, populat
            If PrimeCatID = CatReader("ID") Then
                Do While SubCatReader.Read
                    AddRow(" -" & SubCatReader("SubCat"), Drawing.Color.Transparent, "search.aspx?PrimeCat=" & CatReader("ID") & "&SubCat=" & SubCatReader("ID"))
                Loop
            End If
            ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
        Loop
    End Sub
End Class
0
Comment
Question by:bhermer
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
  • +1
11 Comments
 
LVL 4

Expert Comment

by:Xeavn
ID: 17902630
I would instead use an ArrayList and set it up to use either ViewState or Session.

Protected Property alMyButtonList As ArrayList
      Get
            If Session("MyButtons") Is Nothing Then
                  Session("MyButtons") = New ArrayList()
            End If
            Return Session("MyButtons")
      End Get
      Set(ByVal Value As ArrayList)
            Session("MyButtons") = Value
      End Set
End Property 'alMyButtonList

This should allow you preserve the handles through postback, and access them again.

You will have to change a few things around, since an ArrayList will work a little different than an normal array, but looking at what your doing it seems the better choice, and you will be able to avoid all your ReDim's that you are doing with your current array. If you aren't familar with ArrayList's I can help there as well.

If you really want to keep using a regular Array, you can probably set one up as a Property to use Session as well.


0
 
LVL 23

Expert Comment

by:Jens Fiederer
ID: 17906375
Another suggestion that does not DIRECTLY address your question, but might be useful:

Generate ALL the controls in the original Load event.  After that, simply remove the VISIBILITY of the controls you do NOT want showing.  Controls that are not visible are not even sent to the client, so you are not clogging the pipes.
0
 
LVL 7

Expert Comment

by:ExpertAdmin
ID: 17914073
I think the solution here is to wrap a [If  Not IsPostback Then] around the line that is calling SubPageLoad, or around the control creation code in SubPageLoad:
 If  Not IsPostback Then
      '# set options for the table
        CategoryTbl.BorderStyle = BorderStyle.None
        CategoryTbl.BorderColor = Drawing.Color.Transparent
        CategoryTbl.BorderWidth = 0

        Do While CatReader.Read '# loop through categores
            '#Add category to table
            AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
            'resize the button array
            ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
        Loop
End If

M@
0
 [eBook] Windows Nano Server

Download this FREE eBook and learn all you need to get started with Windows Nano Server, including deployment options, remote management
and troubleshooting tips and tricks

 
LVL 4

Author Comment

by:bhermer
ID: 17914914
Thanks for the comments peeps, my comments below:

Xeavn, A little help on this would be appreciated, I have no idea how to use an ArrayList as buttons!

jensfiederer, Problem I have with this is I still have the issue of getting the button ID after the second time it posts back as I lose the reference to the original control when  I recreate the buttons

ExpertAdmin, If I do this then it wont capture the handle event of the pressed button as it hasent been created when it posts back! so I dont get to do anything on postback!

The bit I dont understand is on postback:

1)  I re-create the buttons in the onload event so I can capture the button event, giving each an incremental command name of 1-10, this matches the original command names on the first render

2) I capture the button press event :

    Public Sub ButtonHandler(ByVal sender As System.Object, ByVal e As System.EventArgs)

3) I read the command name attached to the button that was pressed

    Dim PrimeCatID As Integer = CType(sender, LinkButton).CommandName

4) I 'Try' to destroy the buttons I have created

    ReDim ButtonArray(0)

5) I re-create the buton array, again giving each a command name from 1-10, BUT when I look in the rendered page html the buttons have taken the numbers 11-20, i.e
On initial page load the first button has this on its click code
     javascript:__doPostBack('BrowseBar1$ctl03','')   : notice the 03

But once I have re-rendered the page after postback the ccode is:
     javascript:__doPostBack('BrowseBar1$ctl13','')    : notice the 13

Why is it renumbering the ommand names? I am oviously not destrioying the original buttons with the ReDim ButtonArray(0), but how else can I ensure they are gone?

0
 
LVL 23

Accepted Solution

by:
Jens Fiederer earned 600 total points
ID: 17915167
What I was saying is DON'T recreate the buttons.  Create them once, and then keep only the ones you want to use visible.  That way you have a fixed hierarchy, fixed ids, etc.
0
 
LVL 7

Expert Comment

by:ExpertAdmin
ID: 17915194
I think you have to capture the event BEFORE the load event by calling your event code in the INIT function. I have gone through the exact same thing with dynamic controls...MS apparently never considered that we would actually want to create layouts based on data.

M@
0
 
LVL 4

Author Comment

by:bhermer
ID: 17915207
Hi, Thats a good idea, but how do I do that, I tried storing them in the ViewState, and got an error. So I tried storing them in a session  var, but they just dont come back, the button handler event doesnt get fired, my code:

        If IsPostBack = False Then
            Dim CatReader As MySqlDataReader = CreateReader("SELECT * FROM Categories")

            '# set options for the table
            CategoryTbl.BorderStyle = BorderStyle.None
            CategoryTbl.BorderColor = Drawing.Color.Transparent
            CategoryTbl.BorderWidth = 0

            Do While CatReader.Read '# loop through categores
                '#Add category to table
                AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
                'resize the button array
                ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
            Loop
            Session("ButtonArray") = ButtonArray
        Else
            ButtonArray = Session("ButonArray")
        End If
0
 
LVL 4

Author Comment

by:bhermer
ID: 17915235
ExpertAdmin , Whcih part of my code would I put there, would I cerate the buttons there? sorry if that is a bit of an ignorant question!?
0
 
LVL 7

Assisted Solution

by:ExpertAdmin
ExpertAdmin earned 450 total points
ID: 17915270
No, it is not ignorant at all. I found this particular problem to be very, very frustrating and there is very little in the way of useful information about it out there.

I am trying to remember how I got around this problem. I am pretty sure that I moved the event definition to the init function so that it would be called before my dynamic controls would be destroyed and recreated in the Load event. So if you have a function called "Button_clicked" that handles the click event for your dynamic button, you would define the event in the init section.

The other problem is that you are working in VB and I did it in C#. I am not as familiar with the way VB handles events.

Maybe someone else could talk bhermer through that part of it.

M@
0
 
LVL 4

Assisted Solution

by:Xeavn
Xeavn earned 450 total points
ID: 17915913
Feel free to give this a try Bhermer. I don't know if I did it exactly right, but It should be pretty close. Maybe it will work for you. Instead of removing your buttons and readding them, I just stored them in an arraylist, and reused them as needed.

    Protected Property alMyButtonList As ArrayList
        Get
            If Session("MyButtons") Is Nothing Then
                Session("MyButtons") = New ArrayList()
            End If
            Return Session("MyButtons")
        End Get
        Set(ByVal Value As ArrayList)
            Session("MyButtons") = Value
        End Set
    End Property 'alMyButtonList

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        '### select cetagories one at a time and them
        If Not Page.IsPostBack Then
            Dim CatReader As MySqlDataReader = CreateReader("SELECT * FROM Categories")

            '# set options for the table
            CategoryTbl.BorderStyle = BorderStyle.None
            CategoryTbl.BorderColor = Drawing.Color.Transparent
            CategoryTbl.BorderWidth = 0

            Do While CatReader.Read '# loop through categores
                '#Add category to table
                AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
                'resize the button array
                'ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
            Loop
        End If
    End Sub


    Sub AddCat(ByVal CellText As String, ByVal CellColour As Drawing.Color, ByVal ID As String)
        Dim objRow As TableRow = New TableRow
        Dim objCell As New TableCell

        Dim tmpLinkButton As New LinkButton
        tmpLinkButton.Text = CellText
        tmpLinkButton.CommandName = ID
        AddHandler tmpLinkButton.Click, AddressOf ButtonHandler
       
        If Not alMyButtonList.Contains(tmpLinkButton) Then
            alMyButtonList.Add(tmpLinkButton)
        Else
            'Don't Add the button, since it already exists, just reuse the old one.
        End If
   
        Dim myIndex As Integer = alMyButtonList.IndexOf(tmpLinkButton)

        'ButtonArray(UBound(ButtonArray)) = New LinkButton

        'With ButtonArray(UBound(ButtonArray))
        '    .Text = CellText
        '    .CommandName = ID
        '    AddHandler .Click, AddressOf ButtonHandler
        'End With
       

        objCell.Controls.Add(alMyButtonList.Item(myIndex))   '.Text = "<a href='" & HyperLink & "'>" & CellText & "</a>"
        objRow.BorderColor = Drawing.Color.Transparent
        objRow.Cells.Add(objCell)
        objRow.BackColor = CellColour
        objRow.Font.Size = "10"

        CategoryTbl.Rows.Add(objRow)
    End Sub

    Sub AddRow(ByVal CellText As String, ByVal CellColour As Drawing.Color, ByVal HyperLink As String)

        Dim objRow As TableRow = New TableRow
        Dim objCell As New TableCell
        If HyperLink = "" Then
            objCell.Text = CellText
        Else
            objCell.Text = "<a href='" & HyperLink & "'>" & CellText & "</a>"
        End If
        objRow.BorderColor = Drawing.Color.Transparent
        objRow.Cells.Add(objCell)
        objRow.BackColor = CellColour
        objRow.Font.Size = "10"

        CategoryTbl.Rows.Add(objRow)
    End Sub


    Public Sub ButtonHandler(ByVal sender As System.Object, ByVal e As System.EventArgs)
        '# destroy the button array
        'ReDim ButtonArray(0)
        '# get the cat ID of the button
        Dim PrimeCatID As Integer = CType(sender, LinkButton).CommandName
        '#  destroy the html from the original table so we can build it again
        CategoryTbl.Rows.Clear()
        ' get the button id and populate the sub categories
        Dim SubCatReader As MySqlDataReader = CreateReader("SELECT * FROM subcategories WHERE CatID = " & PrimeCatID)

        Dim CatReader As MySqlDataReader = CreateReader("SELECT * FROM Categories")

        Do While CatReader.Read '# loop through categores
            '#Add category to table
            AddCat("<b>" & CatReader("PrimeCat") & "</b>", Drawing.Color.Transparent, CatReader("ID"))
            '# see if is needs children and if so, populat
            If PrimeCatID = CatReader("ID") Then
                Do While SubCatReader.Read
                    AddRow(" -" & SubCatReader("SubCat"), Drawing.Color.Transparent, "search.aspx?PrimeCat=" & CatReader("ID") & "&SubCat=" & SubCatReader("ID"))
                Loop
            End If
            'ReDim Preserve ButtonArray(UBound(ButtonArray) + 1)
        Loop
    End Sub
End Class
0
 
LVL 4

Author Comment

by:bhermer
ID: 17929663
Right, I have solved this problem by completely changing my plan of attack, what I have done is:

1) Create a table and put my dynamic buttons in it, giving the button command name and the Cell ID where the button sits the same name
2) On postback I recreate the same table exactly so I can capture the button handle
3) on the button handle event I analys which button was pressed, I then cycle through the table looking for the Cell ID that matches the button command name, once I have this I use CategoryTbl.Rows.AddAt command to add my sub category cells below the relevant Cell!

The problem I had was trying to destroy the buttons and re-create them with the SAME command name, NET just wont let you do that for some reason, this way I dont destroy them, just create them on every page load and dynamically insert content at the right place.

Thanks for your partisipation, always helps having ideas bounced off you. I will spluit the points as without your ideas I wouldnt have thought of teh solution.
0

Featured Post

 [eBook] Windows Nano Server

Download this FREE eBook and learn all you need to get started with Windows Nano Server, including deployment options, remote management
and troubleshooting tips and tricks

Question has a verified solution.

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

Summary Displaying images in RichTextBox is a common requirement with limited solutions available. Pasting through clipboard or embedding into RTF content only support static images.  This article describes how to insert Windows control objects int…
It seems a simple enough task, yet I see repeated questions asking how to do it: how to pass data between two forms. In this article, I will show you the different mechanisms available for you to do just that. This article is directed towards the .N…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …

656 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