Responding to dynamically created async postback buttons - asynchronous

When my ASP page is loaded I am reading data from a SQL database into a list of objects, then looping through this list and creating dynamic placeholders, updatepanels, textboxs and buttons which are then added to a main placeholder. Each updatepanel is set to conditional and the unique button is added to the scriptmanager. I tried to create async triggers dynamically but found this is not possible. Below is my code:
Dim plcComments As New PlaceHolder()
plcComments.ID = "plcComments" + Link.ID.ToString()
Dim updComments As New UpdatePanel()
updComments.ID = "updComments" + Link.ID.ToString()
updComments.UpdateMode = UpdatePanelUpdateMode.Conditional
Dim txtComment As New TextBox()
txtComment.ID = "txtComment" + Link.ID.ToString()
txtComment.Text = "txtComment " + Link.ID.ToString() 'Example text
updComments.ContentTemplateContainer.Controls.Add(txtComment)
Dim btnComment As New Button()
btnComment.ID = "btnComment" + Link.ID.ToString()
btnComment.Text = "btnComment" + Link.ID.ToString()
updComments.ContentTemplateContainer.Controls.Add(btnComment)
ScriptManager1.RegisterAsyncPostBackControl(btnComment)
plcComments.Controls.Add(updComments)
In a normal circumstance I understand you would have code behind for each button that acts a trigger. As these buttons are created dynamically with unique names, how can I react to each button when it is pressed?

After looking into the AddHandler function I came up with this dirty method:
AddHandler btnComment.Click, AddressOf Me.Button_Handler
This latches to each button as it is created, points back at the same sub routine, and creates the controls within the subroutine based upon the sender.
Protected Sub Button_Handler(sender As Object, e As EventArgs)
Dim Comment_ID As String = DirectCast(sender, Button).ID.ToString.Remove(0, 3)
Dim txtComment As TextBox = Me.FindControl("txt" & Comment_ID)
Dim plcComment As PlaceHolder = Me.FindControl("plc" & Comment_ID)
Dim updComment As UpdatePanel = Me.FindControl("upd" & Comment_ID)
End Sub
Probably not the cleanest or best way to do it but it works.

Related

OnClick function on dynamic LinkButton?

I'm creating dynamic LinkButton where I assign to it dynamically an ID now I would be able to write an onClick function where I get that ID but after trying to make something like that I had no result:
table.Append("<td><asp:LinkButton runat=""server"" class=""edit btn btn-sm btn-default"" ID=" & reader.GetString("id") & " OnClient=""Delete_User""><i class=""fa fa-trash-o"" aria-hidden=""true""></asp:LinkButton></i></a>")
While here is VB.NET code
Sub Delete_User(sender As Object, e As EventArgs)
Dim clickedBtn As LinkButton = CType(sender, LinkButton)
MsgBox(clickedBtn.ID)
End Sub
The LinkButton is a server control and you cannot render it with same way as you render plain HTML tags from code-behind, it will not work as expected. You need to provide HtmlTableCell instance and bind LinkButton control from there, assumed table is defined as HtmlTable:
' this is just a sample event
Protected Sub SomeEventHandler(sender As Object, e As EventArgs)
Dim table As HtmlTable = New HtmlTable()
Dim row As HtmlTableRow = New HtmlTableRow()
' set the data reader from database here
Dim cell As HtmlTableCell = New HtmlTableCell()
Dim linkbtn As LinkButton = New LinkButton()
linkbtn.ID = reader.GetString("id") ' setting control ID
linkbtn.Text = "Delete User" ' setting link text
linkbtn.CssClass = "edit btn btn-sm btn-default"
AddHandler lnkbutton.Click, AddressOf Delete_User ' assign event handler
' add the control to table cell ('td' element)
cell.Controls.Add(linkbtn)
row.Cells.Add(cell)
table.Rows.Add(row)
' other stuff
End Sub
Note that you should provide server-side click event with Click property which associated with OnClick event, not OnClient nor OnClientClick.
Additional note:
MsgBox cannot be used in ASP.NET because it belongs to WinForms, you need to provide JS alert() function to show message box with RegisterStartupScript or RegisterClientScriptBlock:
Sub Delete_User(sender As Object, e As EventArgs)
Dim clickedBtn As LinkButton = CType(sender, LinkButton)
Dim message As String = "alert('" & clickedBtn.ID & "');"
Page.ClientScript.RegisterClientScriptBlock(Me.[GetType](), "MsgBox", message, True)
End Sub
Related issues:
How to add linkbutton control to table cell dynamically
Creating a link button programmatically
How to add dynamically created buttons to a dynamically created table?

Dynamically generated code-behind button won't fire its event

I have a series of controls (3 labels, 3 text boxes, and 2 buttons) that are created when the user clicks a button on my page. The page does its postback with the commands that will generate these controls. However, when I fill in my textboxes and click one of the newly generated buttons (btnCreate), nothing happens, and the page just reloads once again.
What I want to happen is that when the user clicks btnCreate, it fires its function, and puts the TextBox.Text into a database. But again, when btnCreate is clicked, nothing happens.
Here is the code for the generated buttons (It's the same function that generates the text boxes, which I've excluded here):
Protected Sub createSpecialNotes()
Dim btnCreate As Button = New Button
Dim btnClear As Button = New Button
'Place properties
lblSubject.Text = "subject"
lblSubject.ID = "lblSubject"
lblSubject.Width = 700
lblAgenda.Text = "Agenda Note"
lblAgenda.ID = "lblAgenda"
lblAgenda.Width = 700
lblMinutes.Text = "Minutes Note"
lblMinutes.ID = "lblMinutes"
lblMinutes.Width = 700
btnCreate.Text = "Create"
btnCreate.ID = "btnCreate"
btnClear.Text = "Clear"
btnClear.ID = "btnClear"
'Add handlers for buttons
AddHandler btnCreate.Click, AddressOf btnCreate_Click
AddHandler btnClear.Click, AddressOf btnClear_Click
plhCreateSpecialNotes.Controls.Add(btnCreate)
plhCreateSpecialNotes.Controls.Add(btnClear)
End Sub
And for the sake of simplicity, let's just say btnCreate needs only to display the textboxes' contents.
Edit1: The call for create special notes is on page_preInit. It's call consists of the following
Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
'Find the control that was fired
Dim controlFired As Control = GetPostBackControl(Me.Page)
If (controlFired IsNot Nothing) Then
If (controlFired.ClientID.ToString() = "btnCreateSpecial") Then
Call createSpecialNotes()
End If
If (controlFired.ClientID.ToString() = "btnCreate") Then
'i've tried putting things here to no avail.
End If
End If
End Sub
The function getpostbackcontrol looks like this
Public Shared Function GetPostBackControl(ByVal thePage As Page) As Control
Dim myControl As Control = Nothing
Dim ctrlName As String = thePage.Request.Params.Get("__EVENTTARGET")
If ((ctrlName IsNot Nothing) And (ctrlName <> String.Empty)) Then
myControl = thePage.FindControl(ctrlName)
Else
For Each Item As String In thePage.Request.Form
Dim c As Control = thePage.FindControl(Item)
If (TypeOf (c) Is System.Web.UI.WebControls.Button) Then
myControl = c
End If
Next
End If
Return myControl
End Function
I hope this helps to clear things up as to why I'm having trouble.
What would be really useful here is to know when you're calling createSpecialNotes(). But most probably what you are missing is the life-cycle of the page.
Make sure createSpecialNotes() is called OnInit of your page. Anything after that is too late and your event handler won't be fired.
If OnLoad of your page is reached and you haven't yet bound the handler to your control, then it won't be fired.
I recommend that you read this article carefully. http://msdn.microsoft.com/en-us/library/ms178472.aspx

get value of label when button clicked in nested repeater asp.net vb

I have nested repeaters, each item in the nested repeater has a label and a button on it, i want to beable to access the label.text when the button is clicked, I think i'm nearly there as I can return the index of the repeater and nested repeater that is clicked, i'm just having some trouble finding the label itself.
You might be able to help me without me posting the repeater code. Here is my code behind for when the button is clicked.
Protected Sub btnEditUser_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim btnEditUser As Button = DirectCast(sender, Button)
Dim reClient As RepeaterItem = DirectCast(btnEditUser.NamingContainer.Parent.Parent, RepeaterItem)
Dim reUser As RepeaterItem = DirectCast(btnEditUser.NamingContainer, RepeaterItem)
Dim selectedClient As Integer = reClient.ItemIndex
Dim selectedUser As Integer = reUser.ItemIndex
Dim UserId As Label = DirectCast(reClients.Items(selectedClient).FindControl("lUserName"), Label)
Response.Write(selectedClient & " " & selectedUser & " " & UserId.Text)
End Sub
I'm currently getting this error 'Object reference not set to an instance of an object.' when trying to write the value of UserId.Text so i think i've got it slightly wrong in this line:
Dim UserId As Label = DirectCast(reClients.Items(selectedClient).FindControl("lUserName"), Label)
This is just a guess, but sometimes you get errors like this when not all rows contain the control you're looking for. Often the code loops through the rows in order, hits a header row first that doesn't contain the relevant control, and fails.
Here is a good MSDN article - Locating a Control Inside a Hierarchy of Naming containers.
Private Function FindControlRecursive(
ByVal rootControl As Control, ByVal controlID As String) As Control
If rootControl.ID = controlID Then
Return rootControl
End If
For Each controlToSearch As Control In rootControl.Controls
Dim controlToReturn As Control =
FindControlRecursive(controlToSearch, controlID)
If controlToReturn IsNot Nothing Then
Return controlToReturn
End If
Next
Return Nothing
End Function
Try it,
Dim UserId As Label =DirectCast(FindControlRecursive(repClient,"lUserName"),Label)

Creating buttons dynamically in ListView

I have a following problem. I have a ListView which returns data from SQL table. One of its columns looks like "Ambient/Trance/Goa Trance/House".
All i want to do is parse this column and create buttons for each value, for example a button for "Ambient", a button for "Trance", etc.
I tried to create buttons in ItemDataBound event in the following way:
Dim ListView_Albums_PlaceHolder_Artists As PlaceHolder = e.Item.FindControl("ListView_Albums_PlaceHolder_Artists")
Dim Artists As String() = e.Item.DataItem("album_artists").ToString.Split("/")
Dim ArtistsN As String() = e.Item.DataItem("album_artists_n").ToString.Split("/")
Dim ListView_Albums_Literal_Artists As New Literal
If Artists.Length = 1 Then
ListView_Albums_Literal_Artists.Text = "Artist: "
Else
ListView_Albums_Literal_Artists.Text = "Artists: "
End If
ListView_Albums_PlaceHolder_Artists.Controls.Add(ListView_Albums_Literal_Artists)
For Integer1 As Integer = 0 To Artists.Length - 1
Dim ListView_Albums_LinkButton_Artist As New LinkButton
ListView_Albums_LinkButton_Artist.Text = ArtistsN(Integer1)
ListView_Albums_LinkButton_Artist.CommandName = "Artist"
ListView_Albums_LinkButton_Artist.CommandArgument = Artists(Integer1)
ListView_Albums_LinkButton_Artist.CssClass = "a-03"
ListView_Albums_PlaceHolder_Artists.Controls.Add(ListView_Albums_LinkButton_Artist)
Dim ListView_Albums_Literal As New Literal
ListView_Albums_Literal.Text = ", "
If Not Integer1 = Artists.Length - 1 Then
ListView_Albums_PlaceHolder_Artists.Controls.Add(ListView_Albums_Literal)
End If
Next
They created fine but they didn't work at all. I tried to Add Handler for Click or Command event but it also didn't help.
Please help me to solve my problem!
Edit:
As VinayC suggested I changed ItemDataBound to ItemCreated. That helped, but I faced another problem: as far as I understand e.Item.DataItem or, maybe, e.Item becomes Nothing on PostBacks so the buttons do not work.
How to solve that problem? Thanks once again!
I believe that buttons must be getting created late in page life cycle and hence not responding to events.
You may want to try moving your code in ItemCreated event and use ListView's ItemCommand event to trap these. Yet another suggestion is to assign (different) ID to your link buttons - for example
ListView_Albums_LinkButton_Artist.ID = "A" & Artists(Integer1)
In case, you want to attach an click event handler directly to buttons then ID is must.
So, I solved my problem. The solution wasn't simple but here it is:
In ItemCreated event I firstly count the number of buttons, then save it to ViewState, and only then I create buttons. I had to save the number of buttons to ViewState because on every postback e.Item.DataItem becomes Nothing.
Maybe there is a simplier solution but I found only that one...
Sub OnItemCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs)
Dim ListView_Albums_PlaceHolder_Artists As PlaceHolder = e.Item.FindControl("ListView_Albums_PlaceHolder_Artists")
If Not ListView_Albums_PlaceHolder_Artists Is Nothing Then
If Not e.Item.DataItem Is Nothing Then
ViewState("Length") = e.Item.DataItem("album_artists").ToString.Split("/").Length
End If
If Not ViewState("Length") Is Nothing Then
Dim Length As Integer = ViewState("Length")
For Integer1 As Integer = 0 To Length - 1
Dim ListView_Albums_LinkButton_Artist As New LinkButton
ListView_Albums_LinkButton_Artist.ID = "ListView_Albums_LinkButton_Artist_" & Integer1
ListView_Albums_PlaceHolder_Artists.Controls.Add(ListView_Albums_LinkButton_Artist)
Next
End If
End If
End Sub
Sub OnItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewItemEventArgs)
Dim ListView_Albums_PlaceHolder_Artists As PlaceHolder = e.Item.FindControl("ListView_Albums_PlaceHolder_Artists")
If Not ListView_Albums_PlaceHolder_Artists Is Nothing Then
If Not e.Item.DataItem Is Nothing Then
Dim Artists As String() = e.Item.DataItem("album_artists").ToString.Split("/")
Dim Artists_N As String() = e.Item.DataItem("album_artists_n").ToString.Split("/")
For Integer1 As Integer = 0 To Artists.Length - 1
Dim ListView_Albums_LinkButton_Artist As LinkButton = e.Item.FindControl("ListView_Albums_LinkButton_Artist_" & Integer1)
ListView_Albums_LinkButton_Artist.CommandArgument = Artists(Integer1)
ListView_Albums_LinkButton_Artist.Text = Artists_N(Integer1)
ListView_Albums_LinkButton_Artist.CssClass = "a-03"
Next
End If
End If
End Sub

Dynamically adding controls to a panel within a data repeater

I have a Data Repeater to which I need to add x number of images depending on their existence in the database.
I need the images added within hyperlinks for Javascript functionality. In order to dynamically add the hyperlinks and images I have placed them within a panel in the data repeater and am adding them in the ItemDataBound event.
The problem is that only the first image is being written to the datarepeater.
Protected Sub Repeater1_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles myDataRepeater.ItemDataBound
Dim myPanel As Panel = e.Item.FindControl("pnlImages")
Dim myLink As New System.Web.UI.WebControls.HyperLink
Dim myImage As New System.Web.UI.WebControls.Image
Dim myProperty As String = Request.QueryString("ID")
Dim dirInfo As New DirectoryInfo(Server.MapPath("~/ftp/images/"))
Dim fs_infos() As FileInfo = dirInfo.GetFiles("*" + myProperty.Substring(1) + "*")
For Each fs_info As FileInfo In fs_infos
If fs_info.Name.Substring(8, 1) <> "P" Then
myLink.ID = fs_info.Name
myLink.NavigateUrl = "~/ftp/images/" + fs_info.Name
myLink.Attributes.Add("onClick", "return hs.expand(this)")
myLink.Width = 90
myImage.ID = "img" + fs_info.Name
myImage.ImageUrl = "~/ftp/images/" + fs_info.Name
myImage.Width = 80
myImage.Height = 60
myLink.Controls.Add(myImage)
myPanel.Controls.Add(myLink)
End If
Next fs_info
fs_infos = Nothing
End Sub
Any ideas as to what I am doing wrong - or a better way of doing things?
You create just one Link and one Image object and use it for each iteration. Move the dims of myLink and myImage into the if statement and everything should work.

Resources