VB.NET DataGridView rows - vb.net

NET Hi I'm new in VB NET and I'm trying to check if all values in the same row of a datagridview are the same.
Exemple :
For Each row In DataGridView1.Rows
If 'all values in row are not the same' Then
row.DefaultCellStyle.BackColor = Color.Red
End if
Next
Tell me if there is anything that you don't understand in my question ^^
Thank you in advance for your help! :P

May be better if you use handler of .RowPrepaint
private sub datagridivew_RowPrepaint(sender as Object, e as DataGridViewRowPrePaintEventArgs) Handles datagridview.RowPrePaint
if e.RowIndex >= 0 then
Dim dgvr as DataGridViewRow = DirectCast(sender, DataGridView).Rows(e.RowIndex)
if IsAllValuesAreSame(dgvr) = True Then
dgvr.DefaultCellStyle.BackColor = Color.Red
End If
End If
End Sub
Then you don't need to loop all rows one more time after all rows initialized.
And function for checking all values of row:
private function IsAllValuesAreSame(dgvr as DataGridViewRow) as Boolean
Dim distinctQnt As Int32 = (From cell As DataGridViewCell In dgvr.Cells
Where cell.ColumnIndex >= 0
Select cell.Value).Distinct().Count()
Return (distinctQnt = 1)
End Function

You need to match the value of all the cells in each row with one cell in that row to know if all cells in that row have the same value. Below, I'm giving you the simplest method to do it and I am choosing the value of the first column of each row to verify if the values of other columns in that row are equal to it. If all the columns/cells of a row don't have the same value, then that row's back color will turn red.
For x = 0 To DataGridView1.RowCount - 1
For y = 0 To DataGridView1.ColumnCount - 1
If DataGridView1.Item(y, x).Value = DataGridView1.Item(0, x).Value Then
'yes
Else
'no
DataGridView1.Rows.Item(x).DefaultCellStyle.BackColor = Color.Red
End If
Next
Next

Related

prevent go to next row when duplicated value in `datagridview`

I have datagrid that user will add values in just one column , and i want to prevent duplicated data in this column, i had mange that by the code bellow,
what I want is to keep the selection (focus) in the same editing cell(x)
if the entered data is duplicated, so I tried to get the current row index and return to it if the data is duplicated but its not working.
row_index = DataGridView1.CurrentRow.Index.ToString()
Dim cell As DataGridViewCell = DataGridView1.Rows(row_index).Cells(1)
DataGridView1.CurrentCell = cell
DataGridView1.BeginEdit(True)
NOTE : User will Add barcode number, so he will use barcode scanner or add it manually and press enter key.
Private Sub DataGridView1_RowValidated(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.RowValidated
If DataGridView1.Rows.Count > 2 Then
Dim i As Integer = 0
Dim row_index As Integer
' loop condition will loop while the row count is less or equal to i
While i <= DataGridView1.Rows.Count - 1
Dim j As Integer = 1
' loop condition will loop while the row count is less or equal to j
While j <= DataGridView1.Rows.Count - 1
Dim str As String = DataGridView1.Rows(i).Cells(1).Value()
Dim str1 As String = DataGridView1.Rows(j).Cells(1).Value()
If Not str1 = "" AndAlso Not str = "" Then
If str1 = str Then
'row_index = DataGridView1.SelectedCells.Item(i).RowIndex.ToString()
row_index = DataGridView1.CurrentRow.Index.ToString()
Dim cell As DataGridViewCell = DataGridView1.Rows(row_index).Cells(1)
DataGridView1.CurrentCell = cell
DataGridView1.BeginEdit(True)
Exit Sub
End If
End If
j += 1
End While
i += 1
End While
End If
End Sub
You can try it also in a for loop. This is how I do it. If what you mean is to stop/retain the selection(focus) or go to in a cell/row whenever it is a duplicate with the current data you have. This should work fine.
enter code here
For i = 0 To Datagridview1.Rows.Count - 1
If Datagridview1.Rows(i).Cells(1).Value = DataYouWillInput Then
DataGridView1.CurrentCell = DataGridView1.Rows(i).Cells(1)
Exit for
End If
Next
enter code here
If your condition returns true with the condition of current data and data you'll be adding. Just exit your loop. Use this.
DataGridView1.CurrentCell = DataGridView1.Rows(i).Cells(1)

Datagridview: How to change color of alternate rows having cell value alternate days?

Respected Sir,
I have a datagridview filled with data having various timestamps in one column
And trying to colour rows in range of alternate days like the image above. So far, i am trying like this
Private Sub alternateDaysRows()
For i As Integer = 1 To Me.datagridview1.Rows.Count - 1
If i > 1 Then
Dim myLastRowDate As Date
myLastRowDate = CType(Me.datagridview1.Rows(Me.datagridview1.Rows.Count - 1).Cells(2).Value, DateTime).Date
myCountDate = myLastRowDate.AddDays(1)
For Each row As DataGridViewRow In Me.datagridview1.Rows
If CType(row.Cells(2).Value, DateTime).Date = myCountDate Then
row.DefaultCellStyle.BackColor = Color.WhiteSmoke
End If
Next
End If
Next
End Sub
any suggestions ?
yours faithfully
Murulimadhav
Something along these lines may do what you want:
Private Sub alternateDaysRows()
Dim myLastRow As DataGridViewRow = Nothing
Dim myLastColor = Color.Yellow
Dim isFirstRow As Boolean = True
For Each row As DataGridViewRow In Me.DataGridView1.Rows
If myLastRow IsNot Nothing Then
If DateTime.Parse(myLastRow.Cells(0).Value.ToString).Date <> DateTime.Parse(row.Cells(0).Value.ToString).Date Then
myLastColor = If(myLastColor = Color.Yellow, Color.Red, Color.Yellow)
End If
End If
myLastRow = row
row.DefaultCellStyle.BackColor = myLastColor
Next
This assumes that the cells are sorted in date order and that the values are convertable to a date. It alternates when the date changes rather than on every other day but would highlight when a different day is being viewed.

How to compare DataGridView cell data to DataSet cell data

In a VB.NET WinForms project I'm working on in VS2013 I am detecting when the user changes something in a cell on the CellValueChanged event. When a row in the DataGridView is found that is different from the DataSet I highlight the row in pink.
In my code though, I only know how to iterate through all of the rows, rather than just compare the row that fired the CellValueChanged event to the DataSet.
Here's my current code:
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource(e.RowIndex, e.ColumnIndex)
End Sub
Private Sub CompareDgvToDataSource(ByVal rowIndex As Integer, ByVal columnIndex As Integer)
' Force ending Edit mode so the last edited value is committed
EmployeesBindingSource.EndEdit()
Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanged Is Nothing Then
For Each dt As DataTable In dsChanged.Tables
For Each row As DataRow In dt.Rows
For i As Integer = 0 To dt.Columns.Count - 1
Dim currentColor As System.Drawing.Color = dgvEmployees.AlternatingRowsDefaultCellStyle.BackColor
If Not row(i, DataRowVersion.Current).Equals(row(i, DataRowVersion.Original)) Then
Console.WriteLine("Row index: " & dt.Rows.IndexOf(row))
' This works
dgvEmployees.Rows(rowIndex).DefaultCellStyle.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
Next
Next
End If
End Sub
As you can see, I'm passing the row and column index of the changed cell, so how can I take that and compare it to the specific row and/or cell in the unchanged DataSet?
UPDATE
Nocturnal reminded me that I need to allow for sorting of the DGV, so using row indexes won't work. He offered this as a solution (changed slightly to work with my objects):
If Not dsChanged Is Nothing Then
For Each dtrow As DataRow In dsChanged.Tables("employees").Rows
If DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID.ToString = dgvEmployees.Rows(rowIndex).Cells("employeeID").Value.ToString Then
For i As Integer = 0 To dsChanged.Tables("employees").Columns.Count - 1
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID)
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
End If
Next
End If
However, I'm getting an error on the If DirectCast... line saying "Column named "employeeID" cannot be found." I'm not sure if the error is on the DataSet or on the DGV, but there is an employeeID column in the database and DataSet. There is an employeeID as a bound column for the DataGridView, but it is set to Visible = False. That's the only thing I can think of that could possibly cause that error, but if it's a bound column, I would think it could be compared against as in this case.
FINAL WORKING VERSION
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource("employees", e.RowIndex, e.ColumnIndex)
End Sub
Private Sub CompareDgvToDataSource(ByVal dataSetName As String, ByVal rowIndex As Integer, ByVal columnIndex As Integer)
' Takes a dataset and the row and column indexes, checks if the row is different from the DataSet and colors the row appropriately
EmployeesBindingSource.EndEdit()
Dim dsChanges As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanges Is Nothing Then
For Each dtrow As DataRow In dsChanges.Tables("employees").Rows
If DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID.ToString = dgvEmployees.Rows(rowIndex).Cells("employeeID").Value.ToString Then
For i As Integer = 0 To dsChanges.Tables("employees").Columns.Count - 1
If dtrow.RowState.ToString = DataRowState.Added.ToString Then
' TODO: Color entire new row
ElseIf dsChanges.Tables(dataSetName).Rows(0).HasVersion(DataRowVersion.Original) Then
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.employeesRow).employeeID)
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' TODO: Need to change the BackColor back to what it should be based on its original alternating row color
End If
End If
Next
End If
Next
End If
End Sub
My project has four DGVs in it, so this will eventually be expanded to allow for all four DGVs to be checked for changes.
have a look at this approach it is simlar but only iterating the specific Table
Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
' Pass the row and cell indexes to the method so we can change the color of the edited row
CompareDgvToDataSource(e.RowIndex, e.ColumnIndex, sender.DataSource.datamember.ToString)
End Sub
and comparing the ID of the given Table
Private Sub CompareDgvToDataSource(ByVal rowIndex As Integer, ByVal columnIndex As Integer, tablename As String)
EmployeesBindingSource.EndEdit()
Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()
If Not dsChanged Is Nothing Then
For Each dtrow As DataRow In dsChanged.Tables(tablename).Rows
If DirectCast(dtrow, EmployeesDataSet.EmployeeRow).EmployeeID = dgvEmployees.Rows(rowIndex).Cells("EmployeeID").Value Then
Dim currentColor As System.Drawing.Color = dgvEmployees.AlternatingRowsDefaultCellStyle.BackColor
For i As Integer = 0 To dsChanged.Tables(tablename).Columns.Count - 1
If Not dtrow(i, DataRowVersion.Current).Equals(dtrow(i, DataRowVersion.Original)) Then
Console.WriteLine("Employees ID: " & DirectCast(dtrow, EmployeesDataSet.EmployeeRow).EmployeeID)
' This works
dgvEmployees.Rows(rowIndex).Cells(columnIndex).Style.BackColor = Color.LightPink
Else
' Need to change the BackColor back to what it should be based on its original alternating row color
End If
Next
End If
Next
End If
End Sub
and i am only changing the backcolor of the cell that was changed not the entire row....but depends how you would use that information anyways
EDIT:
with
Console.WriteLine(EmployeesDataSet.Employee(rowIndex)(columnIndex, DataRowVersion.Original).ToString())
Console.WriteLine(EmployeesDataSet.Employee(rowIndex)(columnIndex, DataRowVersion.Current).ToString())
you can see Current and Original Values
123456

Search DataGridView for Integer Then Select Row

The below code should search DataGridView1 which is on the LeaderAccessTable form for an integer that the user inputs into SendFromID, if the DataGridView1's first column contains what the integer that the user has entered into SendFromID then the entire row should be selected. However it doesn't select any rows at all... Can anyone see why? This code is ran from a separate form.
Dim intcount As Integer
For Each Row As DataGridViewRow In LeadersAccessTable.DataGridView1.Rows
If LeadersAccessTable.DataGridView1.Rows(intcount).Cells(0).Value.ToString = SendFromID.Text Then
LeadersAccessTable.DataGridView1.Rows(intcount).Selected = True
End If
Next
MsgBox("Done.")
In the end this code worked.
Dim v_SelectRow As Integer
For counter = 0 To (LeadersAccessTable.DataGridView1.Rows.Count - 1)
For counter2 = 0 To (LeadersAccessTable.DataGridView1.Columns.Count - 1)
If (LeadersAccessTable.DataGridView1.Rows(counter).Cells(0).Value.ToString.Contains(SendFromID.Text)) Then
LeadersAccessTable.DataGridView1.Rows(counter).Cells(0).Selected = True
v_SelectRow = LeadersAccessTable.DataGridView1.CurrentRow.Index
CurrentPoints.Text = LeadersAccessTable.DataGridView1.Item(8, v_SelectRow).Value
'Do Something
Else
'Do Something
End If
Next
Next

Cannot remove rows in datagridview in vb.net

My datagridview is bound to a data table. I want to filter the datagridview without affecting data table. I know one way is to use bindingsource, but binding source will use column names in its filter. But I want to enable users to enter any string in a textbox to filter. So I pass datagridview by reference to a function PassFilter which removes unwanted rows in datagridview. I can see that it does execute rows removal in datagridview. But the problem is that when datagridview is shown on the form, it is unchanged, the same as the data table. I do not understand why rows are not removed on datagridview
The code is as follows:
DataGridView1.DataSource = table
PassFilter(DataGridView1, m_FilterQuick.strFilter.ToLower())
Private Sub PassFilter(ByRef datagridview As DataGridView, ByVal strFilter As String)
Dim i As Integer = 0
Dim j As Integer = 0
Dim containStr As Boolean = False
While i < datagridview.Rows.Count
j = 0
containStr = False
'If all cells in a row does not contain strFilter, delete this row from datagridview
While j < datagridview.Rows(i).Cells.Count
Dim c As DataGridViewCell = datagridview.Rows(i).Cells(j)
If Not c.Value Is DBNull.Value Or Nothing Then
If c.Value.ToString().ToLower().Contains(strFilter) Then
containStr = True
Exit While
End If
End If
j = j + 1
End While
If Not containStr Then
datagridview.Rows.RemoveAt(i)
End If
i = i + 1
End While
End Sub
Your big problem is that you're removing items in the DataGridViewRowCollection as you're iterating through that collection. Even if you're not getting an 'index out of range' error doing this you're going to end up removing the wrong row(s) as the index value of later rows change when you remove earlier rows.
What you should do is instead of removing rows in your row loop, add the row's index to a List(Of Integers).
After you're done iterating through all the rows in your DataGridView, Reverse() your list and use the row index values in your List to remove rows via the RemoveAt() method.
Here's what I mean:
Private Sub PassFilter(ByRef datagridview As DataGridView, ByVal strFilter As String)
Dim i As Integer = 0
Dim j As Integer = 0
Dim containStr As Boolean = False
' Row indexes we'll remove later on.
Dim deleteIndexList As List(Of Integer) = New List(Of Integer)
While i < datagridview.Rows.Count
j = 0
containStr = False
'If all cells in a row does not contain strFilter, delete this row from datagridview
While j < datagridview.Rows(i).Cells.Count
Dim c As DataGridViewCell = datagridview.Rows(i).Cells(j)
' Note: you'll want to enclose the tests for DBNull.Value and Nothing in parens like I show here.
If Not (c.Value Is DBNull.Value And c.Value Is Nothing) Then
If c.Value.ToString().ToLower().Contains(strFilter) Then
containStr = True
Exit While
End If
End If
j = j + 1
End While
If Not containStr Then
' Don't remove rows here or your row indexes will get out of whack!
' datagridview.Rows.RemoveAt(i)
deleteIndexList.Add(i)
End If
i = i + 1
End While
' Remove rows by reversed row index order (highest removed first) to keep the indexes in whack.
deleteIndexList.Reverse()
For Each idx As Integer In deleteIndexList
datagridview.Rows.RemoveAt(idx)
Next
End Sub
Are you displaying the data as read-only, or for edit?
If you're allowing the users to edit, can you find some way to hide the rows you don't want shown, rather than trying to remove them?
If you're displaying this as read-only, you could grab the data after the filtering, and throw it into a new datagridview.... (ugly, yes, but a possible option)
Oh wait... what about if you pass the datagridview by value instead of reference, so your changes at remove will be maintained?