Get row count in ItemDataBound - asp.net

I have a datasource in Page_Load binded to a repeater.
I am writing the results to the page in ItemDataBound but when it's the last row of data I require it to do something slightly different.
How do I access the row count of a data source in Page_Load from within ItemDataBound of the repeater?
I've tried:
Dim iCount As Integer
iCount = (reWorkTags.Items.Count - 1)
If e.Item.ItemIndex = iCount Then
'do for the last row
Else
'do for all other rows
End If
But both e.Item.ItemIndex and iCount equal the same for every row.
Thanks for any help.
J.

But both e.Item.ItemIndex and iCount equal the same for every row.
This is because the items are still binding. The Count is going to be +1 of the current item index, when binding.
I think it would be best to do this after the repeater has bound entirely.
Therefore you could add the following to your Page_Load:
rep.DataBind()
For each item as repeateritem in rep.items
if item.ItemIndex = (rep.Items.Count-1)
'do for the last row
else
'do for all other rows
end if
Next
Note: I've just added rep.DataBind() to show this should be ran after the repeater is bound.

Was tring to avoid using Sessions but got it working with one in the end.
I just created a session of the row count and could access that from ItemDataBound.
Protected Sub reWorkTags_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles reWorkTags.ItemDataBound
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
Dim rowView As System.Data.DataRowView
rowView = CType(e.Item.DataItem, System.Data.DataRowView)
Dim link As New HyperLink
link.Text = rowView("tag")
link.NavigateUrl = rowView("tagLink")
link.ToolTip = "View more " & rowView("tag") & " work samples"
Dim comma As New LiteralControl
comma.Text = ", "
Dim workTags1 As PlaceHolder = CType(e.Item.FindControl("Linkholder"), PlaceHolder)
If e.Item.ItemIndex = Session("iCount") Then
workTags1.Controls.Add(link)
Else
workTags1.Controls.Add(link)
workTags1.Controls.Add(comma)
End If
End If
End Sub

This is an old question but I had this exact situation recently. I needed to write out markup for every item except the last.
I created a private member variable in my user control class and set it to the count property of the data source being bound to my repeater and subtracted 1 from it. Since an index is zero based, the index value is one off from the count.
private long itemCount { get; set; }
In Page_Load or whatever method you call DataBind:
//Get the count of items in the data source. Subtract 1 for 0 based index.
itemCount = contacts.Count-1;
this.repContacts.DataSource = contacts;
this.repContacts.DataBind();
Finally, in your binding method
//If the item index is not = to the item count of the datasource - 1
if (e.Item.ItemIndex != itemCount)
Do Something....

When databinding is happening the datasource will be set for the repeater. So in your ItemDataBound event handler you can get it and check it against your item index. This would avoid the use of Session or local variables.
var datasource = (ICollection)reWorkTags.DataSource;
if (e.Item.ItemIndex + 1 == datasource.Count)
{
// Do stuff
}

Related

Check Checkboxes in a gridview based on a non-boolean value from a stored procedure

I am trying to check checkboxes on certain rows of a gridview based off of a selection from a dropdown. I have a gridview where the first column is a checkbox (cb_pain), and the second column is an ID (DrugID). The user makes a selection from the dropdown list, this fires a stored procedure. The stored procedure returns all of the DrugID's that need to be checked. I'm able to pull the DrugID from the data like this: dt.Rows(0)("pain1").ToString() That tells me DrugID for a row that needs to be checked.
Basically I would like to check the checkbox on the row where DrugID = dt.Rows(0)("pain1").ToString()
I think this needs to be done on the selectedindexchange of the dropdown.
My gridview looks like this: (sorry for the dot's, I couldn't figure out how to tab)
cb_pain........DrugID...............Field1
x.................3...................other data
x.................23.................other data
x.................24.................other data
x.................37.................other data
How can I use this to check the checkbox on the row that has the right DrugID?
I've tried a couple of different DirectCast things, but no success. Can anyone point me in the right direction?
Thanks
Another option that I tend to prefer is to make use of the RowDataBound event of the GridView. As each row gets data bound to it, this event gets called. What you would do is find the DrugID control and check its value. If it is what you want, do something.
First, let your GridView know of the event.
<asp:GridView ID="gvDrugs" runat="server" OnRowDataBound="gvDrugs_RowDataBound">
</asp:GridView>
Then handle the event. If the DrugID is 23, find the CheckBox and check it.
Protected Sub gvDrugs_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
Dim lblDrugID As Label = e.Row.FindControl("lblDrugID")
If lblDrugID.Text = "23" Then
Dim cbPain As CheckBox = e.Row.FindControl("cbPain")
cbPain.Checked = True
End If
End If
End Sub
**Note here that I am assuming the types of controls to be labels and checkboxes. You have not shown your markup, so this is the best I can do.
After your edit, I would probably agree with you. This is something that could be done in the SelectedIndexChanged event of the DropDownList. Get the list of DrugIDs that need to be checked and iterate each row of your GridView, checking those that match.
Protected Sub dropdown_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim uniqueDrugIDs As HashSet(Of String) = New HashSet(Of String)()
' Here we assume dt is some sort of global variable as your question above implies
For Each dr As DataRow In dt.Rows
uniqueDrugIDs.Add(dr("drugID").ToString())
Next
For Each gvRow As GridViewRow In gvDrugs.Rows
Dim lblDrugID As Label = gvRow.FindControl("lblDrugID")
If (uniqueDrugIDs.contains(lblDrugID.Text)) Then
Dim cbPain As CheckBox = gvRow.FindControl("cbPain")
cbPain.Checked = True
End If
Next
End Sub
You can go for that kind of loop that will go through all your rows :
for (int x = 0; x < NameOfYourGrid.Rows.Count; x++)
{
GridViewRow row = (GridViewRow)NameOfYourGrid.Rows[x];
if(row("pain1").ToString() == "23")
CheckBox chk = (CheckBox)row.Cells[0].FindControl("The_Name_Of_The_Control");
}
Or, if you wich to do it on the binding ;
In the .aspx file put an explicit property on your check box :
<asp:CheckBox ID="chkInside" runat="server" Checked='<%# CheckForChecked(Container.DataItem as Whatever_the_object_is) %>' ></asp:CheckBox>
And link that event in the code behind :
protected bool CheckForChecked(Whatever_the_object_is OBJ)
{
try
{
return (bool) OBJ.Boolean_value;
// here you are supposed to have a compete Object
// OBJ.ID is suposed to be the rigth id
}
catch
{
return false;
}
}
Then the checkBox will be checked if the value is true on the gridview binding. You won't need the ID if your binding is done correctly.
I took j-f's response and got it to work when place in the right spot. At the end of filling the dataset I added this code:
Dim row As GridViewRow
For Each row In gv_pain.Rows
If row.RowType = DataControlRowType.DataRow Then
Dim lblDrugID As Label = row.FindControl("lbl_DrugID")
If lblDrugID.Text = dt.Rows(0)("pain1").ToString() Then
Dim cbPain As CheckBox = row.FindControl("CheckBoxPain")
cbPain.Checked = True
End If
End If
Next
This goes through my rows and check the correct ones.

Need to display total price in gridview

just been trying to display my total price from a column in my footer row.
here is my code to try that but it doesnt seem to be even going through it when i put a break point in
Sub gvPayments_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
' add the UnitPrice and QuantityTotal to the running total variables
invoiceTotal += Convert.ToDecimal(DataBinder.Eval(e.Row.DataItem, "Total"))
ElseIf e.Row.RowType = DataControlRowType.Footer Then
e.Row.Cells(0).Text = "Total:"
' for the Footer, display the running totals
e.Row.Cells(5).Text = invoiceTotal.ToString("c")
e.Row.Cells(5).HorizontalAlign = HorizontalAlign.Right
e.Row.Font.Bold = True
End If
End Sub
If you need any more of my code, just ask!
I like to use a method that doesn't require handling any events. It just uses a TemplateField and a couple different functions. In your GridView, make the column like this:
<asp:TemplateField HeaderText="Total">
<ItemTemplate><%#DisplayAndAddToTotal(Eval("Total").ToString(), "Total")%></ItemTemplate>
<FooterTemplate><%#GetTotal("Total")%></FooterTemplate>
</asp:TemplateField>
The second parameter to DisplayAndAddToTotal can be any string you want as long as you use the same string in GetTotal. I usually just use the field name again though. Here are the two functions used, DisplayAndAddToTotal and GetTotal. They use a Hashtable to store the totals so that it works with any number of columns you want to add up. And they also work with counting the number of "True"s for a Boolean field.
Protected total As Hashtable = New Hashtable()
Protected Function DisplayAndAddToTotal(itemStr As String, type As String) As Double
Dim item As Double
If itemStr = "True" Then
item = 1
ElseIf Not Double.TryParse(itemStr, item) Then
item = 0
End If
If total.ContainsKey(type) Then
total(type) = Double.Parse(total(type).ToString()) + item
Else
total(type) = item
End If
Return item
End Function
Protected Function GetTotal(type As String) As Double
Try
Dim result As Double = Double.Parse(total(type).ToString())
Return result
Catch
Return 0
End Try
End Function

Changing SelectedIndex of DropDownList in repeater results in all instances of DropDownList having the same Selected Index

I have a user control that contains a repeater. The repeater contains some control, including a dropDownList with id 'ddlPallet'. The repeater is bound to a dataset in the user controls' Page_Load event.
I'm using the ItemDataBound event of the repeater to change the SelectedValue of the dropdownlist based on a value from the dataset.
The problem I'm having is that when the page renders, ALL of the dropdownlists' selectedValue are set to the last selectedValue specified - i.e. If there are 8 rows in the dataset and row 8 is 'N' then the selected index of all instances of 'ddlPallet' will have a selectedValue of 'N'
Here's my ItemDataBound code:
Protected Sub rptCavities_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles rptCavities.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim ddl As DropDownList
ddl = e.Item.FindControl("ddlPallet") 'get the dropdown
ddl.Items.AddRange(Me._arrPallets) 'add items
Dim drv As DataRowView = CType(e.Item.DataItem, DataRowView) 'get the data row being bound
Dim sv As String = "" 'get the value of the 'pallet' column from the dataset
If Trim(drv("Pallet").ToString()) <> "" Then
sv = drv("Pallet").ToString()
Else
sv = "N"
End If
ddl.SelectedValue = sv 'set the selected value of the dropdown list for this item
'debug
System.Diagnostics.Debug.WriteLine("----")
System.Diagnostics.Debug.WriteLine("Control ID: " & ddl.ID)
System.Diagnostics.Debug.WriteLine("Control Client ID: " & ddl.ClientID)
System.Diagnostics.Debug.WriteLine(ddl.SelectedIndex.ToString() & " - " & ddl.SelectedItem.ToString() & " - " & ddl.SelectedValue)
System.Diagnostics.Debug.WriteLine("")
End If
End Sub
The debug output shows that the appropriate SelectValue is being set per item/per dropDownList:
Control ID: ddlPallet
Control Client ID: Cure1_rptCavities_ctl01_ddlPallet
4 - FL - FL
Control ID: ddlPallet
Control Client ID: Cure1_rptCavities_ctl02_ddlPallet
3 - EP - EP
Control ID: ddlPallet
Control Client ID: Cure1_rptCavities_ctl03_ddlPallet
0 - N - N
..etc.
This is driving me nuts. I assume I have some kind of scoping error that is causing the last-set index value to apply to all instances of the dropDownList in the repeater, but I'm having no luck figuring out where or why. If I bind the same data to a label in the ASCX file using "Text='<%#Container.DataItem("Pallet")%>'" the correct data is displayed.
It may be because you're adding the same items to the drop down list in every case, rather than binding the dropdownlist to the source data. This way, they all share a common set of items, and if you set Selected = true to one item, it'll be true for every dropdownlist that contains that item.
Potentially an interesting technique, but probably not what you want.

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)

Iterate over rows/checkboxes in a RadGrid

I have a Telerik RadGrid with a GridTemplateColumn that contains a checkbox, as follows:
<telerik:GridTemplateColumn HeaderText="MINE" UniqueName="MyTemplateColumn">
<ItemTemplate>
<asp:CheckBox id="MyCheckBox" runat="server"></asp:CheckBox>
</ItemTemplate>
</telerik:GridTemplateColumn>
I want to set the box to be "checked" based on a value read from the database. I could handle the ItemDataBound event and read the database when each row is bound, but that results in n lookups. Instead, I want to handle DataBound, and then set all the values at once. So, in that method, I want code like this:
// read all values from database first, then...
foreach(var chkbox in MyRadGrid.MasterTableView.Columns.FindByUniqueName("MyTemplateColumn").FindControl("MyCheckBox")) {
chkbox.Checked = oneValue;
}
That doesn't work, because FindControl isn't a method of GridColumn, and it won't generate an iterable list of the checkboxes. What is the correct way to iterate through the checkboxes in the template column? Thanks!
Telerik got back to me on their forums with the answer, as follows:
foreach (GridDataItem item in MyRadGrid.MasterTableView.Items)
{
CheckBox chk = (CheckBox)item.FindControl("MyCheckBox");
// Set the value here
}
Hope this is useful for someone!
I am having the same issue.. this was how I did it..
'Created a local hashtable to use now and otherwise
Private _GroupMembers As New Hashtable
'Loaded it up on page load
Private Function GetMembers() As Boolean
Try
Dim da As New DataAccess
Dim ht As New Hashtable
Dim i As Int16 = 0
ht.Add("CAC", Session("cac"))
ht.Add("GroupID", _GroupID)
If da.GetData("rap_spGetGroupMemberList", ht) = True Then
If da.SQLDataRows.HasRows Then
While da.SQLDataRows.Read()
i = i + 1
_GroupMembers.Add(i, da.SQLDataRows("UserID"))
End While
End If
da.SQLDataRows.Dispose()
End If
da = Nothing
Catch ex As Exception
Console.Write(ex.Message)
End Try
End Function
'Check for contains
Protected Sub RadGrid2_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid2.ItemDataBound
Try
If e.Item.IsDataBound Then
If Not e.Item.DataItem("UserID") Is Nothing Then
If Not IsDBNull(e.Item.DataItem("UserID")) Then
Dim UserID As Long = e.Item.DataItem("UserID")
If _GroupMembers.ContainsValue(UserID) Then
e.Item.Selected = True
End If
End If
End If
End If
Catch ex As Exception
Console.Write(ex.Message)
End Try
End Sub

Resources