Need to display total price in gridview - asp.net

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

Related

VB.net For Each Loop Not Accounting for First Datarow

I am currently looping through a data gridview in Visual Studio, The Loop works well and the code does pretty much what I want,
My only problem is that it seems to skip, or not account for the first row in my gridview, I have looked online to resolve this but cannot find anything,
I was wondering if i could get some assistance with this...
Here is my code for the loop:
'Checks the flags for montor/expiry date to set red or green cells
'------------------------------------------------------------------
For Each Row As GridViewRow In GridView3.Rows
'-----------------------------------------------------------------------------------------
Dim MonitorVal As String = GridView3.DataKeys(e.Row.RowIndex).Values("Monitor").ToString
If MonitorVal.Contains("Yes") Then
Dim IsExtention As String = GridView3.DataKeys(e.Row.RowIndex).Values("FileName").ToString
If IsExtention = "" Or IsExtention = Nothing Or IsExtention = "Null" Then
'set red
'--------
e.Row.BackColor = Drawing.Color.LightPink
Else
'else green
'-----------
e.Row.BackColor = Drawing.Color.LightGreen
End If
Else
'else green
'-----------
e.Row.BackColor = Drawing.Color.LightGreen
End If
Next
I guess that "first row in gridview" actually means the header-row of the grid. That is not returned from GridView.Rows, only rows with DataControlRowType.DataRow are returned. You can get it only in events like RowDataBound or RowCreated. I would suggest to use RowDataBound in this case:
Protected Sub GridView3_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView3.RowDataBound
Select Case e.Row.RowType
Case DataControlRowType.Header
' ... '
Case DataControlRowType.DataRow
' ... '
Case DataControlRowType.Footer
' ... '
End Select
End Sub
Documentation:
Only rows with their RowType property set to
DataControlRowType.DataRow are stored in the Rows collection. The
GridViewRow objects that represent the header, footer, and pager rows
are not included in the collection.

Getting text from labels inside gridview cells (VB)

VB
I've got a gridview in which I need to use template columns, therefore instead of being able to retrieve text straight from the cell, it's inside of a label. All the labels have different ids as well so I would like to programmatically retrieve the label inside a cell then look at the text inside the label.
This is what I have got at the moment, however it never manages to return the text and instead returns the empty string ("").
Public Function ReturnLabelText(ByVal c As TableCell) As String
For Each lb In c.Controls
If lb.[GetType]() = GetType(Label) Then
Return CType(lb, Label).Text()
End If
Next
Return ""
End Function
The function is called on this line:
doc.ReplaceText("#" + gridView.HeaderRow.Cells(i).Text.ToLower, ReturnLabelText(row.Cells(i)).Replace(" ", "").Replace(vbCr, ""))
You have to use GridViewRow.FindControl("ControlID") to get the reference of the Label.
So for example, if you want to loop loop all rows:
For Each row As GridViewRow In Me.GridView1.Rows
Dim label = DirectCast(row.FindControl("LabelID"), Label)
Dim text As String = label.Text
' ... '
Next
But if you want to set it's text on databinding i'd use the GridView.RowDataBound event instead:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
Select Case e.Row.RowType
Case DataControlRowType.DataRow
Dim label = DirectCast(e.Row.FindControl("LabelID"), Label)
Dim text As String = label.Text
' ... '
End Select
End Sub
You can even get the DataSource of each row via e.Row.DataItem to access all fields.
If you have a TableCell and you want to get all labels in it you could also use OfType:
Dim firstLabel = c.Controls.OfType(Of Label)().FirstOrDefault()
If firstLabel IsNot Nothing Then Return firstLabel.Text
Return Nothing

asp.net vb gridview coulours based on previous row

I have a GridView displaying results from sql server, all values are supposed to follow on the previous value e.g. 3373 must be before 3372. I need to colour the row on the gridview as soon as the value does not follow the previous value. Sometimes the values are missing so I need to identify if a value is missing or not.
You could use the OnRowDataBound event to store the last value and compare. Something like this:
Private _lastRowValue As Integer = -1
Protected Sub OnGridViewRowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
If _lastRowValue <> -1 Then
' read current row value, compare and then format, e.g. like this
e.Row.Cells(1).Text = "<i>" + e.Row.Cells(1).Text + "</i>"
End If
_lastRowValue = ... ' read value from cell
End If
End Sub

Get row count in ItemDataBound

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
}

Gridview Header with sort-icon

I am binding a data set to a GridView in VB .net. I have some custom sorting setup, and want to display an icon next to the header if one of my 3 options is selected.
I've read a lot of methods in doing this, and I see Gridviews even have a ASC and DESC header style I can associate with the view. I have 2 problems with this, though:
I am sorting a List with linq on Sort Trigger, then binding it to the datagrid.
The reason I do it this way, is I want to maintain multiple sort levels, ordering by 3 columns rather than 1.
Edit for clarity
Specifically what I want to do is loop through the value of a GridView's Header text, see if it matches what I have saved in viewstate, and if so add an image for that header in particular. Something essentially like below, however headerRow.Cells(y).Text is always returning "", even when the header has text:
Sub gvPatronData_RowCreated(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
Dim savedSortDirection(), savedSortColumn() As String
Dim headerRow As GridViewRow = gvPatronData.HeaderRow
'this sets the values of these variables
'as strings equal to the text displayed in the header of the gridview
_patronBl.SplitPatronSort(savedSortDirection, SortDirection, savedSortColumn, SortColumn)
If SortDirection <> "" Then
If e.Row.RowType = DataControlRowType.Header Then
For x = 0 To savedSortDirection.Length - 1
For y = 0 To headerRow.Cells.Count - 1
If headerRow.Cells(y).Text = savedSortColumn(x) Then
If savedSortDirection(x) = "Ascending" Then
Dim bGStyle As New System.Web.UI.WebControls.Style()
bGStyle.CssClass = "upSort"
headerRow.Cells(y).ApplyStyle(bGStyle)
Else
Dim bGStyle As New System.Web.UI.WebControls.Style()
bGStyle.CssClass = "downSort"
headerRow.Cells(y).ApplyStyle(bGStyle)
End If
End If
Next
Next
End If
End If
End Sub
Have you tried to loop the GridView's Columns instead of the the GridViewRow's Cell-Collection? A DataControlField has a HeaderText property.
For Each col As DataControlField In gvPatronData.Columns
If col.HeaderText = savedSortColumn(x) Then
If savedSortDirection(x) = "Ascending" Then
Dim bGStyle As New System.Web.UI.WebControls.Style()
bGStyle.CssClass = "upSort"
headerRow.Cells(gvPatronData.Columns.IndexOf(col)).ApplyStyle(bGStyle)
Else
Dim bGStyle As New System.Web.UI.WebControls.Style()
bGStyle.CssClass = "downSort"
headerRow.Cells(gvPatronData.Columns.IndexOf(col)).ApplyStyle(bGStyle)
End If
End If
Next
This is how I ended up doing it. Actually drilling into the table objects was where I was coming up short before.
Sub gvPatronData_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
Dim savedSortDirection(), savedSortColumn() As String
Dim columnCollection As DataControlFieldCollection = gvPatronData.Columns
_patronBl.SplitPatronSort(savedSortDirection, SortDirection, savedSortColumn, SortColumn)
If e.Row.RowType = DataControlRowType.Header Then
For x = 0 To savedSortDirection.Length - 1
For Each col As DataControlField In columnCollection
If col.HeaderText = _headerDictionary(savedSortColumn(x)) Then
If savedSortDirection(x) = "Ascending" Then
e.Row.Cells(gvPatronData.Columns.IndexOf(col)).Attributes.Add("Style", _
"background-image: url(images/arrow_up.png);background-repeat:no-repeat;background-position: 96% 50%;")
Else
e.Row.Cells(gvPatronData.Columns.IndexOf(col)).Attributes.Add("Style", _
"background-image: url(images/arrow_down.png);background-repeat:no-repeat;background-position: 96% 50%;")
End If
End If
Next
Next
End If
_headerDictionary : This was a dictionary of my DataField to HeaderText strings, since my savedSortColumn was the data field to sort on.
Def:
Public Function ColumnDataFieldToHeaderTextDictionary() As Dictionary(Of String, String)
Dim dict As New Dictionary(Of String, String)
dict.Add("FirstName", "First Name")
dict.Add("LastName", "Last Name")
dict.Add("Phone", "Phone Number")
dict.Add("Phone2", "Alternate Phone Number")
dict.Add("Email", "Email")
Return dict
End Function

Resources