473,396 Members | 1,783 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

trouble with click events on dynamically created link buttons

I've read quite a few different message on various boards and for some
reason I'm still having trouble wrapping my head around this viewstate
maintenance and trying to get these dynamically created link buttons
to stay wired up to their click events.

I have what is basically a simply survey question generation page. The
page first displays a few static fields and a dropdownlist of various
options for the user to select. When the user selects an option from
the list the page will generate a new table with 5 rows of textboxes,
drop down lists, and link buttons (to delete a row if desired). There
is also a static insert button to allow users to add additional rows
if needed.

Saving the data in the fields during postback isn't an issue, but I'm
stuck in two situations depending on how I adjust the code. First is
that I put the rebuilding of the controls in the Page_load and users
are forced to click twice on the static Insert Row button to add a row
or they have to click twice on a dynamic Delete Row link button to
remove a row. If I take the rebuilding of the controls out of the
Page_Load then the Insert Row button works fine, but clicking on a
Delete Row link button causes the click event to not fire and all the
dynamic controls disappear from the page.

Does anyone have any suggestions on what I need to do to fix this so
it's written correctly and will operate as intended? (if you need more
detail or code please ask)

Thank you for your help.

--Code Snippets (this setup requires 2 clicks on a button before the
click event appears to do anything--

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

If Not IsPostBack Then
LoadQuestionTypes()
End If

RebuildControls()

End Sub
---------------------------
Private Sub ddlQuestionType_SelectedIndexChanged(ByVal sender As
System.Object, ByVal e As System.EventArgs) Handles
ddlQuestionType.SelectedIndexChanged

....
BuildEmptyFive()
....

End Sub
--------------------------
Private Sub BuildEmptyFive()

Dim IDArray As New ArrayList
Dim tblAnswers As New Table
Dim x As Integer

For x = 1 To 5

Dim row As New TableRow
Dim ID As String

ID = Left(System.Guid.NewGuid.ToString, 8)

Dim cell1 As New TableCell
cell1.Controls.Add(BuildTextBox("txtChoice-" & ID, 140))

Dim cell2 As New TableCell
cell2.Controls.Add(BuildDropDownList("ddlFamily-" & ID, 150,
"Family"))

Dim cell3 As New TableCell
cell3.Controls.Add(BuildDropDownList("ddlAttribute-" & ID, 150,
"Attributes"))

Dim cell4 As New TableCell
cell4.Controls.Add(BuildTextBox("txtScore-" & ID, 40))

Dim cell5 As New TableCell
cell5.Controls.Add(BuildLinkButton("lnkDelete-" & ID))

row.Cells.Add(cell1)
row.Cells.Add(cell2)
row.Cells.Add(cell3)
row.Cells.Add(cell4)
row.Cells.Add(cell5)

tblAnswers.Rows.Add(row)
IDArray.Add(ID)
Next

plhDynControls.Controls.Add(tblAnswers)

'Insert Array containing ID of each row
If IsNothing(ViewState.Item("IDArray")) Then
ViewState.Add("IDArray", IDArray)
Else
ViewState.Item("IDArray") = IDArray
End If

End Sub
------------------------------
Private Sub btnInsert_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnInsert.Click

'Add a new ID to the viewstate which will cause a new row to be
inserted when the viewstate is rebuilt
Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)
IDArray.Add(Left(Guid.NewGuid.ToString, 8))
ViewState.Item("IDArray") = IDArray

'RebuildControls() 'unremark this and remove from page_load to get
insert button to work perfectly (delete no workie though)

End If

End Sub
---------------------------------
Private Sub lnkDelete_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)

Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)

Dim ID As String = Right(CType(sender, LinkButton).ID.ToString, 8)
IDArray.RemoveAt(IDArray.IndexOf(ID))

ViewState.Item("IDArray") = IDArray

End Sub
-----------------------------------
this is how I generate the link button dynamically
Private Function BuildLinkButton(ByVal name As String) As LinkButton

Dim lnkLink As New LinkButton
lnkLink.ID = name
lnkLink.Text = "Delete"
AddHandler lnkLink.Click, AddressOf lnkDelete_Click

Return lnkLink

End Function
-----------------------------------
Private Sub RebuildControls()

If IsNothing(ViewState.Item("IDArray")) Then
Exit Sub
End If

Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)

Dim tblAnswers As New Table
Dim x As Integer

For x = 0 To IDArray.Count - 1

Dim row As New TableRow

Dim cell1 As New TableCell
cell1.Controls.Add(BuildTextBox("txtChoice-" &
Convert.ToString(IDArray.Item(x)), 140, Request.Form.Item("txtChoice-"
& Convert.ToString(IDArray.Item(x)))))

Dim cell2 As New TableCell
cell2.Controls.Add(BuildDropDownList("ddlFamily-" &
Convert.ToString(IDArray.Item(x)), 150, "Family",
Request.Form.Item("ddlFamily-" & Convert.ToString(IDArray.Item(x)))))

Dim cell3 As New TableCell
cell3.Controls.Add(BuildDropDownList("ddlAttribute-" &
Convert.ToString(IDArray.Item(x)), 150, "Attributes",
Request.Form.Item("ddlAttribute-" &
Convert.ToString(IDArray.Item(x)))))

Dim cell4 As New TableCell
cell4.Controls.Add(BuildTextBox("txtScore-" &
Convert.ToString(IDArray.Item(x)), 40, Request.Form.Item("txtScore-" &
Convert.ToString(IDArray.Item(x)))))

Dim cell5 As New TableCell
cell5.Controls.Add(BuildLinkButton("lnkDelete-" &
Convert.ToString(IDArray.Item(x))))

row.Cells.Add(cell1)
row.Cells.Add(cell2)
row.Cells.Add(cell3)
row.Cells.Add(cell4)
row.Cells.Add(cell5)

tblAnswers.Rows.Add(row)

Next

plhDynControls.Controls.Add(tblAnswers)

End Sub
----------------------------
Let me know if seeing anything else might help. Thanks again.

Feb 20 '07 #1
5 6732
Amoril

You cannot use NewGuid function for ids because it'll generate different id
on every call (it means also on every postback) so events for all dynamically
created controls will not be fired. And you want be able to find a value
entered by the user. Use x (loop counter) with contact prefix instead. Have
also in mind you should recreate controls in page_init (but do not access
viewstate at this stage because it’s simply not collected yet) as they will
automatically recreate their state.

Hope it helps
"Amoril" wrote:
I've read quite a few different message on various boards and for some
reason I'm still having trouble wrapping my head around this viewstate
maintenance and trying to get these dynamically created link buttons
to stay wired up to their click events.

I have what is basically a simply survey question generation page. The
page first displays a few static fields and a dropdownlist of various
options for the user to select. When the user selects an option from
the list the page will generate a new table with 5 rows of textboxes,
drop down lists, and link buttons (to delete a row if desired). There
is also a static insert button to allow users to add additional rows
if needed.

Saving the data in the fields during postback isn't an issue, but I'm
stuck in two situations depending on how I adjust the code. First is
that I put the rebuilding of the controls in the Page_load and users
are forced to click twice on the static Insert Row button to add a row
or they have to click twice on a dynamic Delete Row link button to
remove a row. If I take the rebuilding of the controls out of the
Page_Load then the Insert Row button works fine, but clicking on a
Delete Row link button causes the click event to not fire and all the
dynamic controls disappear from the page.

Does anyone have any suggestions on what I need to do to fix this so
it's written correctly and will operate as intended? (if you need more
detail or code please ask)

Thank you for your help.

--Code Snippets (this setup requires 2 clicks on a button before the
click event appears to do anything--

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

If Not IsPostBack Then
LoadQuestionTypes()
End If

RebuildControls()

End Sub
---------------------------
Private Sub ddlQuestionType_SelectedIndexChanged(ByVal sender As
System.Object, ByVal e As System.EventArgs) Handles
ddlQuestionType.SelectedIndexChanged

....
BuildEmptyFive()
....

End Sub
--------------------------
Private Sub BuildEmptyFive()

Dim IDArray As New ArrayList
Dim tblAnswers As New Table
Dim x As Integer

For x = 1 To 5

Dim row As New TableRow
Dim ID As String

ID = Left(System.Guid.NewGuid.ToString, 8)

Dim cell1 As New TableCell
cell1.Controls.Add(BuildTextBox("txtChoice-" & ID, 140))

Dim cell2 As New TableCell
cell2.Controls.Add(BuildDropDownList("ddlFamily-" & ID, 150,
"Family"))

Dim cell3 As New TableCell
cell3.Controls.Add(BuildDropDownList("ddlAttribute-" & ID, 150,
"Attributes"))

Dim cell4 As New TableCell
cell4.Controls.Add(BuildTextBox("txtScore-" & ID, 40))

Dim cell5 As New TableCell
cell5.Controls.Add(BuildLinkButton("lnkDelete-" & ID))

row.Cells.Add(cell1)
row.Cells.Add(cell2)
row.Cells.Add(cell3)
row.Cells.Add(cell4)
row.Cells.Add(cell5)

tblAnswers.Rows.Add(row)
IDArray.Add(ID)
Next

plhDynControls.Controls.Add(tblAnswers)

'Insert Array containing ID of each row
If IsNothing(ViewState.Item("IDArray")) Then
ViewState.Add("IDArray", IDArray)
Else
ViewState.Item("IDArray") = IDArray
End If

End Sub
------------------------------
Private Sub btnInsert_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnInsert.Click

'Add a new ID to the viewstate which will cause a new row to be
inserted when the viewstate is rebuilt
Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)
IDArray.Add(Left(Guid.NewGuid.ToString, 8))
ViewState.Item("IDArray") = IDArray

'RebuildControls() 'unremark this and remove from page_load to get
insert button to work perfectly (delete no workie though)

End If

End Sub
---------------------------------
Private Sub lnkDelete_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)

Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)

Dim ID As String = Right(CType(sender, LinkButton).ID.ToString, 8)
IDArray.RemoveAt(IDArray.IndexOf(ID))

ViewState.Item("IDArray") = IDArray

End Sub
-----------------------------------
this is how I generate the link button dynamically
Private Function BuildLinkButton(ByVal name As String) As LinkButton

Dim lnkLink As New LinkButton
lnkLink.ID = name
lnkLink.Text = "Delete"
AddHandler lnkLink.Click, AddressOf lnkDelete_Click

Return lnkLink

End Function
-----------------------------------
Private Sub RebuildControls()

If IsNothing(ViewState.Item("IDArray")) Then
Exit Sub
End If

Dim IDArray As ArrayList
IDArray = CType(ViewState.Item("IDArray"), ArrayList)

Dim tblAnswers As New Table
Dim x As Integer

For x = 0 To IDArray.Count - 1

Dim row As New TableRow

Dim cell1 As New TableCell
cell1.Controls.Add(BuildTextBox("txtChoice-" &
Convert.ToString(IDArray.Item(x)), 140, Request.Form.Item("txtChoice-"
& Convert.ToString(IDArray.Item(x)))))

Dim cell2 As New TableCell
cell2.Controls.Add(BuildDropDownList("ddlFamily-" &
Convert.ToString(IDArray.Item(x)), 150, "Family",
Request.Form.Item("ddlFamily-" & Convert.ToString(IDArray.Item(x)))))

Dim cell3 As New TableCell
cell3.Controls.Add(BuildDropDownList("ddlAttribute-" &
Convert.ToString(IDArray.Item(x)), 150, "Attributes",
Request.Form.Item("ddlAttribute-" &
Convert.ToString(IDArray.Item(x)))))

Dim cell4 As New TableCell
cell4.Controls.Add(BuildTextBox("txtScore-" &
Convert.ToString(IDArray.Item(x)), 40, Request.Form.Item("txtScore-" &
Convert.ToString(IDArray.Item(x)))))

Dim cell5 As New TableCell
cell5.Controls.Add(BuildLinkButton("lnkDelete-" &
Convert.ToString(IDArray.Item(x))))

row.Cells.Add(cell1)
row.Cells.Add(cell2)
row.Cells.Add(cell3)
row.Cells.Add(cell4)
row.Cells.Add(cell5)

tblAnswers.Rows.Add(row)

Next

plhDynControls.Controls.Add(tblAnswers)

End Sub
----------------------------
Let me know if seeing anything else might help. Thanks again.

Feb 20 '07 #2
The only place that I use NewGuid to assign the ID's is in the
BuildEmptyFive sub (only fired after the user selects an item from the
drop down), for RebuildingControls sub I pull the ID's out of the
IDArray in the ViewState, so that shouldn't be an issue.

Moving the RebuildControls() sub from Page_Load to Page_Init actually
made the issue worse, now when I click on the static Insert Row button
or the dynamics link buttons to delete a row, all the dynamic controls
disappear. The static button fires it's event, but the link buttons
don't. Perhaps I'm not understanding what you mean by that since
without accessing the IDArray in the viewstate I won't know how many
controls need to be recreated.

Any more detail you could provide would be appreciated.

Feb 20 '07 #3
Hi again,

Oh yes, you're right but no need for that. it's easier to use row index and
a constant prefix for a particular control type (attribute, score,etc). I'll
try to provide a fully working example later on today.

take care
--
Milosz
"Amoril" wrote:
The only place that I use NewGuid to assign the ID's is in the
BuildEmptyFive sub (only fired after the user selects an item from the
drop down), for RebuildingControls sub I pull the ID's out of the
IDArray in the ViewState, so that shouldn't be an issue.

Moving the RebuildControls() sub from Page_Load to Page_Init actually
made the issue worse, now when I click on the static Insert Row button
or the dynamics link buttons to delete a row, all the dynamic controls
disappear. The static button fires it's event, but the link buttons
don't. Perhaps I'm not understanding what you mean by that since
without accessing the IDArray in the viewstate I won't know how many
controls need to be recreated.

Any more detail you could provide would be appreciated.

Feb 20 '07 #4
Hi again,

Actually we have to use guid because you can delete row, which i didn't pick
up before. Anyway, i created fully working example for you. You should be
fine from this point

-- begin aspx code --

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Survey.aspx.vb"
Inherits="Survey" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DropDownList runat="server" ID="questions" AutoPostBack="true">
<asp:ListItem Text="Please Select a Question..." />
<asp:ListItem Text="What are your names?" />
<asp:ListItem Text="Name all girlfriends you have had in your life" />
</asp:DropDownList>
<asp:Panel runat="server" ID="container" />
<asp:Panel runat="server" ID="surveyOptions">
<asp:Button ID="btnAddRow" runat="server" Text="Add row" />
<asp:Button ID="btnSubmit" runat="server" Text="Submit Survey"/>
</asp:Panel>
</div>
</form>
</body>
</html>
-- end aspx code --

-- begin vb.net code --
Partial Class Survey
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Me.Load
RecreateRows()
End Sub
Protected Sub questions_SelectedIndexChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles questions.SelectedIndexChanged

Const DefaultRowCount As Integer = 5

' clear everything
IDs.Clear()

If CType(sender, DropDownList).SelectedIndex >= 0 Then
' create x default empty rows
For i As Integer = 1 To DefaultRowCount
IDs.Add(GenerateId())
Next
End If

RecreateRows()

End Sub

Private Sub RecreateRows()

container.Controls.Clear()

For Each id As String In IDs
AddAnswerRow(id)
Next

surveyOptions.Visible = IDs.Count 0

End Sub

Private Const RowIdPrefix As String = "row"
Private Const TextBoxIdPrefix As String = "txt"
Private Const DropDownListIdPrefix As String = "ddl"

Private Sub AddAnswerRow(ByVal id As String)

Dim panel As Panel
Dim textBox As TextBox
Dim linkButton As LinkButton
Dim dropDownList As DropDownList

' row panel
panel = New Panel()
panel.ID = RowIdPrefix & id

' answer text box
textBox = New TextBox()
textBox.ID = TextBoxIdPrefix & id

' delete button
linkButton = New LinkButton()
linkButton.ID = "btn" & id
linkButton.Text = "delete"
linkButton.CommandArgument = id
AddHandler linkButton.Command, New CommandEventHandler(AddressOf
DeleteAnswerRow)

dropDownList = New DropDownList()
dropDownList.ID = DropDownListIdPrefix & id
dropDownList.Items.Add(New ListItem("Value0", "0"))
dropDownList.Items.Add(New ListItem("Value1", "1"))
dropDownList.Items.Add(New ListItem("Value2", "2"))

panel.Controls.Add(textBox)
panel.Controls.Add(dropDownList)
panel.Controls.Add(linkButton)
container.Controls.Add(panel)

End Sub

Private Sub DeleteAnswerRow(ByVal source As Object, ByVal e As
CommandEventArgs)

Dim id As String = CType(e.CommandArgument, String)
Dim control As Control = container.FindControl(RowIdPrefix & id)

If (Not control Is Nothing) Then
container.Controls.Remove(control)

Dim index As Integer = IDs.IndexOf(id)
If index <-1 Then
IDs.RemoveAt(index)
End If

End If

End Sub

Private ReadOnly Property IDs() As ArrayList
Get
Dim value As Object = ViewState("IDs")
If value Is Nothing Then
value = New ArrayList()
ViewState("IDs") = value
End If
Return value
End Get
End Property

Private Function GenerateId() As String
Return Guid.NewGuid().ToString("N")
End Function

Protected Sub btnAddRow_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles btnAddRow.Click

Dim id As String = GenerateId()

IDs.Add(id)
AddAnswerRow(id)

End Sub

Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles btnSubmit.Click

' obtain results
Dim textBox As TextBox
Dim dropDownList As DropDownList

For Each id As String In IDs

'
' text box value
'
textBox = CType(container.FindControl(TextBoxIdPrefix & id), TextBox)

If (Not textBox Is Nothing) Then
Dim textBoxValue As String = textBox.Text
End If

'
' drop down list selected value
'
dropDownList = CType(container.FindControl(DropDownListIdPrefix & id),
DropDownList)

If (Not dropDownList Is Nothing) Then
Dim dropDownListValue As String = dropDownList.SelectedValue
End If

Next
End Sub

End Class

-- end vb.net code --
Milosz
"Milosz Skalecki [MCAD]" wrote:
Hi again,

Oh yes, you're right but no need for that. it's easier to use row index and
a constant prefix for a particular control type (attribute, score,etc). I'll
try to provide a fully working example later on today.

take care
--
Milosz
"Amoril" wrote:
The only place that I use NewGuid to assign the ID's is in the
BuildEmptyFive sub (only fired after the user selects an item from the
drop down), for RebuildingControls sub I pull the ID's out of the
IDArray in the ViewState, so that shouldn't be an issue.

Moving the RebuildControls() sub from Page_Load to Page_Init actually
made the issue worse, now when I click on the static Insert Row button
or the dynamics link buttons to delete a row, all the dynamic controls
disappear. The static button fires it's event, but the link buttons
don't. Perhaps I'm not understanding what you mean by that since
without accessing the IDArray in the viewstate I won't know how many
controls need to be recreated.

Any more detail you could provide would be appreciated.
Feb 20 '07 #5
Excellent, thank you very much for your help, it's working great.

Feb 21 '07 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Liqun Xu | last post by:
Hallo NG, I created a Button with Click-Event dynamically: System.Web.UI.WebControls.Button bt_1 = new Button(); bt_1.Click += new EventHandler(bt_1_click); and I implemented the Funktion...
2
by: Michael Johnson Jr. | last post by:
here is the problem, I have a table with dynamic buttons and events. On buton click of said row, it would clear the rows in the table, and repopulate it. This works fine the first time you run...
1
by: Earl Teigrob | last post by:
PROBLEM: When a user control is loaded into a PlaceHolder control more than once, the events do not fire on the first click of a control on the dynamically loaded user control. In other words, the...
1
by: Gopal Krish | last post by:
I'm have coded a simple menu (using link buttons as menu items) in a user control to be reused across many ASPX pages. In the page_load method I dynamically create the link buttons as follows ...
1
by: AndrewMBaldwin | last post by:
Ok, this is going to be a long post, so I apologize in advance, but if it was an easy question I would have probably found an answer somewhere out here by now... The short story of this is that...
0
by: prashantnurvi | last post by:
I have programaticaaly created several Link Buttons on my ASPX page, I would like to raise the Click event of these Link buttons, passing in appropriate parameters depending on the Link button I...
3
by: Mark | last post by:
Assume you want to dynamically add one to many link button controls to a web page dynamically at run time. Each link button needs to post back and execute code. As the link buttons are created at...
5
by: moonie | last post by:
I have an msn style c# windows application with a form and panel on it. A news list is drawn from the database and dynamically added via labels, link lables during form loading. In this...
5
matheussousuke
by: matheussousuke | last post by:
Hello, I'm using tiny MCE plugin on my oscommerce and it is inserting my website URL when I use insert image function in the emails. The goal is: Make it send the email with the URL...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.