VB.net For Each Loop Not Accounting for First Datarow - asp.net

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.

Related

Telerik radgrid row color issue

In my code I have this sub to handle changing row colors depending on the contents of a column called "backorder" which is bit in sqlserver.
When I test if it is True or 1 it executes the main "IF" code twice which is correct for my datatable. 2 rows display as backorder = True. However the grid remains the normal color. If I uncomment the else code block, ALL cells in that column are orange regardless of content and the execution still passed thru the main "IF" twice. I am quite confused by this behavior. If it was CSS interfering, why would it let the orange color work? I have tried a dozen variations of code which all posters say should work...
Please help! I have spent most of the day trying to unravel this!
Protected Sub RadGrid1_ItemDataBound(sender As Object, e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound
If TypeOf e.Item Is GridDataItem Then
Dim item As GridDataItem = DirectCast(e.Item, GridDataItem)
If item("backorder").Text = "True" Or item("backorder").Text = "1" Then
item("backorder").BackColor = System.Drawing.Color.Red
Else
'item("backorder").BackColor = System.Drawing.Color.Orange
End If
End If
End Sub
Your problem is that item("backorder") returns an object of type TableCell, not a row. Therefore, when setting item("backorder").BackColor = System.Drawing.Color.Red you are setting the cell in the column backorder's BackColor, not the entire rows backcolor. If the Column backorder is not visible, you wont see any change.
Try the following code:
Protected Sub RadGrid1_ItemDataBound(sender As Object, e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound
If TypeOf e.Item Is GridDataItem Then
Dim item As GridDataItem = DirectCast(e.Item, GridDataItem)
If item("backorder").Text = "True" Or item("backorder").Text = "1" Then
item.BackColor = Drawing.Color.Red
Else
item.BackColor = System.Drawing.Color.Orange
End If
End If
End Sub
What this does is check the column 'backorder', and then sets the entire rows BackColor by setting the BackColor for the GridDataItem.
Check out Shinu's answer in the following post. Telerik Forum Post
It may be related to the Boolean evaluation you're doing. You've accounted for "True" and 1, but there are others: "true", and -1 come immediately to mind. You might try this instead:
Protected Sub RadGrid1_ItemDataBound(sender As Object, e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound
If TypeOf e.Item Is GridDataItem Then
Dim item As GridDataItem = DirectCast(e.Item, GridDataItem)
If Convert.ToBoolean(item("backorder").Text) = True Then
item("backorder").BackColor = System.Drawing.Color.Red
Else
item("backorder").BackColor = System.Drawing.Color.Orange
End If
End If
End Sub
That way, you're letting the built-in Convert object handle the heavy-lifting on the "truthiness" of the statement contained in the string.

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

Change gridview row forecolor based on column field value

I have a value in one of my gridview column which will determine if the entire row's value should be in red color. I did the below but somehow every single row is red colored. Please kindly advice. Thanks.
Protected Sub uigvList_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles uigvList.RowCreated
If e.Row.RowType = DataControlRowType.DataRow Then
If Not (DataBinder.Eval(e.Row.DataItem, "VoidOn")) Is Nothing Then ' This is the condition, if this field is not blank then I want to the entire row to have red colored values.
e.Row.BackColor = Drawing.Color.Firebrick
End If
End If
End Sub
Maybe DBNull.Value?
If (DataBinder.Eval(e.Row.DataItem, "VoidOn")) IsNot DBNull.Value Then ...
If e.Row.DataItem("VoidOn") IsNot DBNull.Value Then ...
PS: You can check VoidOn value in the debug mode, just set breakpoint to the code row.

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

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