Creating buttons dynamically in ListView - asp.net

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

Related

Can't update data when value is assigned to textboxes in load page

My problem is probably stupid due to my inexperience to programming but please help.
So, I set some textboxes to values from my other page so the user can edit their Task and see what their task was original and edit from there.
The problem is that I set those values in Page Load so when I tried to update it, it updated the original value not the new one that entered because the page load return the old value. Because of this I cannot update my database to new value.
Is there anyway to approaches this problem or to fix this? Like should I place the code somewhere else?
Edit: Ok so I did some more research and found that my problem could maybe be solved by using IsPostBack but I don't understand how to use this code. The only thing I kinda understand is that it is used to return the page to before it got refresh by page load?
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
If Session("Editing") IsNot Nothing Then
btnCreate.Visible = False
btnEdit.Visible = True
Dim Form As FormViewRow = CType(Session("Editing"), FormViewRow) 'get data from the the formview in Home page
Dim Title As Label = CType(Form.FindControl("TitleLabel"), Label)
txtTitle.Text = Title.Text
Dim description As Label = CType(Form.FindControl("DescriptionLabel"), Label)
txtDescription.Text = description.Text
Dim diff As Label = CType(Form.FindControl("DifficultyLabel"), Label)
ddlDifficulty.Text = diff.Text
Dim taskID As Label = CType(Form.FindControl("IDLabel"), Label)
Dim whatID As String = taskID.Text
Session("EditTaskID") = taskID.Text
End If
End Sub
Ok so I was just playing around with IsPostBack and managed to get it to work.
All I did was put my code in an If statement IsPostBack is not equal True Then... Since I'm still learning can someone explain the meaning of IsPostBack in the simplest terms?
It's fine if no one explain it to me. My problem is solved and thank you Amin for taking your time trying to help me. (:
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
If IsPostBack <> True Then
If Session("Editing") IsNot Nothing Then
btnCreate.Visible = False
btnEdit.Visible = True
Dim Form As FormViewRow = CType(Session("Editing"), FormViewRow) 'get data from the the formview in Home page
Dim Title As Label = CType(Form.FindControl("TitleLabel"), Label)
txtTitle.Text = Title.Text
Dim description As Label = CType(Form.FindControl("DescriptionLabel"), Label)
txtDescription.Text = description.Text
Dim diff As Label = CType(Form.FindControl("DifficultyLabel"), Label)
ddlDifficulty.Text = diff.Text
Dim taskID As Label = CType(Form.FindControl("IDLabel"), Label)
Dim whatID As String = taskID.Text
Session("EditTaskID") = taskID.Text
End If
End If
End Sub
I don't know whether your editing page is opened in the same window or a new one. In first scenario, you can save edited values somewhere like Session and restore them in main page's Page_Load server event. According to 2nd scenario, you can use some simple javascript codes to reflex data changes to main page.

trying get total from grid view textbox

i want to get value from grid view text box in Text Change Event but error comes
Object refrence is not set of an instance of an Object
Protected Sub onDebitChange(ByVal sender As Object, ByVal e As EventArgs)
Dim a, b As Integer
With GridView3
Dim rows As Integer = .Rows.Count
For i As Integer = 0 To rows - 1
Dim txtDebit As TextBox = CType(GridView3.Rows(i).FindControl("TotalDebit"), TextBox)
a = Val(txtDebit.Text)
b += a
Next
DebitBalance.Text = b
End With
End Sub
i also had tried for each loop but error is same
please help
You need to put the name of the ItemTemplate control correctly, in onDebitChange method please fix the control name to "Debit" not "TotalDebit" only:
Dim txtDebit As TextBox = CType(GridView3.Rows(i).FindControl("Debit"), TextBox)
Hope this helps.

Accessing Controls on ListView Edit Command

In my ListView I have an ItemTemplate and EditItemTemplate which look something like this, respectively.
------->
When I click the "Edit" button, and it switches to the EditItemTemplate view on the right, I want to prefill the Textbox and select the corresponding option in the DropDownList. How can I do this?
Before you say to use something like the following, please know that I've already explored every possible variation I can think of. Sorry to be so demanding, but please be prepared to walk me through this one if you answer. ^.^ I've been stuck on this issue for literally months :(
Dim lv As ListView = DirectCast(sender, ListView) 'sender is the ListView on the ItemCommand event
Dim ddl As DropDownList = DirectCast(lv.Items(0).FindControl("NewProductName_ddl"), DropDownList)
Dim tb As TextBox = DirectCast(lv.Items(0).FindControl("NewProductName_tb"), TextBox)
UPDATE - RAWR!!
Oh my freaking goodness, SO CLOSE, but no cigar. The following code worked for prefilling when only one item was in the ListView, but when more than one items exist, it throws a NullReferenceException :(
'PROBLEM WAS HERE: Compare to the working code in my answer.
Protected Sub NewProduct_ItemDataBound(ByVal sender As ListView, ByVal e As ListViewItemEventArgs) Handles NewProduct.ItemDataBound
If sender.EditIndex > -1 Then
Dim ddl As DropDownList = DirectCast(e.Item.FindControl("NewProductName_ddl"), DropDownList)
Dim tb As TextBox = DirectCast(e.Item.FindControl("NewProductName_cb"), TextBox)
ddl.Items.FindByValue(sender.DataKeys(sender.EditIndex)("ID").ToString).Selected = True 'Prefills the DropDownList
tb.Text = sender.DataKeys(sender.EditIndex)("Product").ToString 'Prefills the TextBox
End If
End Sub
EUREKA!!
I am elated beyond imagination!! All caps, nor bold do justice to how happy I am right now :)
First I wanna give props to this question which got me pointed in the right direction. Now onto the answer, which is the most ideal variation I have found of the answer provided in the above link:
The ItemDataBound event is the key, but it's important to note that this event will fire for each item that exists in your ListView and for that reason, you must be careful in your approach. Here are two options that worked equally well for me.
Option 1 - Most elegant; only runs FindControl on the item in question rather than all items.
Protected Sub NewProduct_ItemDataBound(ByVal sender As ListView, ByVal e As ListViewItemEventArgs) Handles NewProduct.ItemDataBound
Dim i As Integer = sender.EditIndex
If i = e.Item.DataItemIndex Then
Dim ddl As DropDownList = DirectCast(e.Item.FindControl("NewProductName_ddl"), DropDownList)
Dim tb As TextBox = DirectCast(e.Item.FindControl("NewProductName_cb"), TextBox)
ddl.Items.FindByValue(sender.DataKeys(i)("ID").ToString).Selected = True 'Prefills the DropDownList
tb.Text = sender.DataKeys(i)("Product").ToString 'Prefills the TextBox
End If
End Sub
Option 2 - Based on the referenced question, but with a crucial check to ensure non-null object.
Protected Sub NewProduct_ItemDataBound(ByVal sender As ListView, ByVal e As ListViewItemEventArgs) Handles NewProduct.ItemDataBound
Dim i As Integer = sender.EditIndex
If i > -1 Then
Dim ddl As DropDownList = DirectCast(e.Item.FindControl("NewProductName_ddl"), DropDownList)
Dim tb As TextBox = DirectCast(e.Item.FindControl("NewProductName_cb"), TextBox)
If Not IsNothing(ddl) Then
ddl.Items.FindByValue(sender.DataKeys(i)("ID").ToString).Selected = True 'Prefills the DropDownList
End If
If Not IsNothing(tb) Then
tb.Text = sender.DataKeys(i)("Product").ToString 'Prefills the TextBox
End If
End If
End Sub
I may make improvements to this answer later, but this did the trick for me. :)
Great post! I had the same problem and you saved me hours of trial and error. Just wanted to point out that when using your first option with .NET Framework 3.5 or lower, DataItemIndex isn't available. To work around it you can replace
If i = e.Item.DataItemIndex Then
With
If i = DirectCast(e.Item, IDataItemContainer).DataItemIndex Then

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)

How can i add a row to a data-bound gridview without causing viewstate errors?

I'm trying to add a row grouping row to my data-bound gridview. It works fine on the first response, but at the postback i got the "Failed to load viewstate" error.
There is the code for the GridView's RowDataBound event:
Private Sub AddGroupingRow(ByRef eRow As GridViewRow, ByVal Css As String, ByVal ColSpan As Integer, ByVal Txt As String)
Dim cell As New TableCell()
cell.ColumnSpan = ColSpan
cell.CssClass = "Spacing FieldCell"
cell.Text = Txt
Dim row As New GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal)
row.CssClass = Css
row.Cells.Add(cell)
Dim tbl As Table
tbl = eRow.Parent
tbl.Rows.AddAt(eRow.RowIndex + 1, row)
End Sub
Private Prev_Client_ID As Integer = -1
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim dr As Data.DataRowView = TryCast(e.Row.DataItem, Data.DataRowView)
If dr IsNot Nothing AndAlso dr.Row.RowState <> Data.DataRowState.Added Then
Dim Client_ID As Integer = dr.Item("Client_ID")
If Client_ID <> Prev_Client_ID Then AddGroupingRow(e.Row, "Group", 8, dr.Item("Client_Name"))
Prev_Client_ID = Client_ID
End If
End If
End Sub
I know that it's easier to create the grouping rows at the datasource, but deriving from this code, i want to create some base to other grids at the site.
Try this link. it should help you. I too had the same problem. The only way to resolve is a proper understanding of viewstate.
After some thinking, the answer could not be simpler: disable the viewstate of the gridview.
I was re-binding the datasource at every paging or sorting, so the need for the viewstate was minimum, except for the PageSize and PageIndex, that i became forced to keep track manually.
This is a considerable trade-off: things like PageSize and PageIndex must be managed manually afterwards, since their state are keeped by the ViewState.
So, even doing exactly what i was meant to do, i've decided to adopt an simple alternative solution:
If Cliente_ID <> Cliente_ID_Anterior Then
For i As Integer = 0 To e.Row.Cells.Count - 1
e.Row.Cells(i).Style("border-top") = "solid 1px #777777"
Next
e.Row.Cells(0).Style("border-bottom") = "none"
Else
e.Row.Cells(0).Text = " "
e.Row.Cells(0).Style("border-top") = "none"
e.Row.Cells(0).Style("border-bottom") = "none"
End If
It still groups the column, but in another way, and is more sort friendly. I could use rowspans and turn cells invisible, but it would be harder to keep. Besides, I'll need to paint the line when the user moves the mouse over it, and a rowspan would hinder a lot.

Resources