Delete UNSELECTED rows in a datagridview - vb.net

Hi I have a datagridview with multiselection set to true.
How would I go about letting a user delete all BUT the selected rows in a datagridview?
I tried this, but it doesn't seem to work:
For Each r As DataGridViewRow In DataGridView1.Rows
If r.Selected = False Then
DataGridView1.Rows.Remove(r)
End If
Next

For Each loops use an Enumerator, and you're not supposed to change the data source for an enumerator while you're still looping through it.
There's likely a better way, but if all else fails you should be able to do this by adding references to each unselected row to a new list, and then looping through the list to remove them rows from the grid.

Try this:
For Each r As DataGridViewRow In DataGridView1.Rows
If r.Selected = False Then
Dim row As String = r.ToString.Split("=")(1)(0)
DataGridView1.Rows(row).Visible = False
End If
Next

I suggest you to use LINQ here
'This will selects all the selected rows in your Datagridview
Dim sel_rows As List(Of DataGridViewRow) = (From row In DataGridView1.Rows.Cast(Of DataGridViewRow)() _
Where row.Selected = False).ToList()
If MsgBox(String.Format("Do you want to delete {0} row(s)?", sel_rows.Count) _
, MsgBoxStyle.Information + MsgBoxStyle.YesNo + MsgBoxStyle.DefaultButton3) = MsgBoxResult.Yes Then
For Each row As DataGridViewRow In sel_rows
If row.DataBoundItem IsNot Nothing Then
DataGridView1.Rows.Remove(row)
End If
Next
End If
Note : MsgBox() is optional !

Related

How to Retrieve a new declared DataGridViewRow's value by Column Name (Not by index)?

I am attempting to store an exact copy of a DataGridViewRow into the same row's tag, everything works fine and the results are as it should be... except that when I try to retrieve the value using the column Name(at the last line of the code), it tells me that the column name doesn't exist. But if I use the index, everything works fine.
I have tried using the method CreateCells() or Clone() the structure of the original table but still does not work.
I could stick with using the index. But I would prefer to obtain the values by Column Name. is that possible?
''Create and populate a datagridview with one row
Dim DGV As New DataGridView
DGV.Columns.Add("No1", "No1")
DGV.Columns.Add("No2", "No2")
DGV.Columns.Add("No3", "No3")
Dim Objects As New List(Of Object)
Objects.Add("1")
Objects.Add("2")
Objects.Add("3")
DGV.Rows.Add(Objects.ToArray)
'' Loop to store a copy of itself into the Row's Tag
For Each selectedrows As DataGridViewRow In DGV.Rows
Dim DataGridViewRow As New DataGridViewRow
Dim CellArray As New List(Of Object)
DataGridViewRow.CreateCells(DGV) ''I have tried DataGridViewRow = selectedrow.clone and it still doesnt work
For Each Cell As DataGridViewCell In selectedrows.Cells
CellArray.Add(Cell.Value)
Next
DataGridViewRow.SetValues(CellArray.ToArray)
selectedrows.Tag = DataGridViewRow
Next
DGV.Rows(0).Cells(0).Value = "Change"
MessageBox.Show(DGV.Rows(0).Cells(0).Value) ''Works (Output: Change)
MessageBox.Show(DGV.Rows(0).Tag.Cells(0).Value) ''Works (Output: 1)
MessageBox.Show(DGV.Rows(0).Cells("No1").Value) ''Works (Output: Change)
MessageBox.Show(DGV.Rows(0).Tag.Cells("No1").Value) ''Doesnt Work (Output: System.ArgumentException: 'Column named No1 cannot be found.
Parameter name: columnName')
How about if you Try to change your lines:
Dim rwIdx = 0
For Each selectedrows As DataGridViewRow In DGV.Rows
Dim myDataGridViewRow As New DataGridViewRow
myDataGridViewRow = DGV.Rows(rwIdx)
rwIdx = rwIdx + 1
selectedrows.Tag = myDataGridViewRow
Next
The above only will refer to the same row, not clone the data, and below, I will copy the selectedrows to another datagridview:
Dim DGV As New DataGridView
DGV.Columns.Add("No1", "No1")
DGV.Columns.Add("No2", "No2")
DGV.Columns.Add("No3", "No3")
Dim Objects As New List(Of Object)
Objects.Add("1")
Objects.Add("2")
Objects.Add("3")
DGV.Rows.Add(Objects.ToArray)
'' Loop to store a copy of itself into the Row's Tag
Dim DataGridViewRow As New DataGridViewRow
Dim myRowIdx As Integer = 0
For Each selectedrows As DataGridViewRow In DGV.Rows
DataGridViewRow = New DataGridViewRow
Dim dgv2 As New DataGridView
For Each col As DataGridViewColumn In DGV.Columns
dgv2.Columns.Add(DirectCast(col.Clone, DataGridViewColumn))
Next
For Each Cell As DataGridViewCell In selectedrows.Cells
dgv2.Rows(0).Cells(Cell.ColumnIndex).Value = Cell.Value
Next
selectedrows.Tag = dgv2.Rows(0)
Next
MessageBox.Show(DGV.Rows(0).Cells(0).Value.ToString) ''Works (Output: 1)
MessageBox.Show(DirectCast(DGV.Rows(0).Tag, DataGridViewRow).Cells(0).Value.ToString) ''Works (Output: 1)
DGV.Rows(0).Cells(0).Value = "Change"
MessageBox.Show(DGV.Rows(0).Cells(0).Value.ToString) ''Works (Output: Change)
MessageBox.Show(DirectCast(DGV.Rows(0).Tag, DataGridViewRow).Cells(0).Value.ToString) ''Works (Output: 1)
MessageBox.Show(DGV.Rows(0).Cells("No1").Value.ToString) ''Works (Output: Change)
MessageBox.Show(DirectCast(DGV.Rows(0).Tag, DataGridViewRow).Cells("No1").Value.ToString) ''Works (Output: 1)

vb.net datagridview checkbox loop error

i am currently looping through datagridview1 checkbox column (column1) and if the checkbox is checked, the value of cell from column3 must change.
My below code is working fine when datagridview1.DefaultView.RowFilter = Nothing
However it is not working when the DefaultView.RowFilter is enabled.
For Each row As DataGridViewRow In DataGridView1.Rows
Dim isSelected As Boolean = Convert.ToBoolean(row.Cells(0).Value)
If isSelected Then
row.Cells(3).Value = ComboBox2.Text
End If
Next
Assume i have selected 5 checkboxes, but only 1 record will change and others 4 will remain same as it is. This happens only when the datagridview1 row filter is enabled.
Just for fun try...
For i As Integer = 0 To DataGridView1.Rows.Count - 2
'Your code here
Next
Note the -2 Apparently the grid is counting the last row with the star and nothing in it as a row.
after research in google i am able to fix it.
Try
For i = DataGridView1.Rows.Count - 1 To 0 Step -1
If (DataGridView1.Rows(i).Cells(0).Value = True) Then
DataGridView1.Rows(i).Cells("Shift").Value = ComboBox2.Text
End If
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try
Thanks Guys!

Search using textbox VB

I need to search DataGridView by date. If I enter 2/11/2017 in text box, I want grid to show me rows that contain this date. Date column in my DataGridView is named AppointmentDate and is created in SQL Server. Type of this column is only date.
I saw this, but I am using Entity Framework model, I don't know how to realize it.
dgvPacientet.CurrentCell = Nothing
Dim found As Boolean = False
For Each row As DataGridViewRow In dgvPacientet.Rows
row.Visible = row.Cells("Dt_terminit").Value = txtData.Text
If row.Visible Then found = True
Next
If Not found Then MsgBox("Item not found")`
Simply show or hide the rows that contain the text you want.
DataGridView1.CurrentCell = Nothing
Dim found as Boolean = false
For Each row As DataGridViewRow In DataGridView1.Rows
Row.Visible = Not IsDBNull(row.Cells("DT_Terminit").Value) andalso row.Cells("DT_Terminit").Value = TextBox5.Text
If Row.Visible then found = true
Next
If Not found Then MsgBox("Item not found")
However you really need to parse that textbox to make sure it is a date first and if that cell contains a true Date, you need to convert the test into a date.
Dim DT As Date
If Not Date.TryParse(TextBox5.Text, DT) Then
MsgBox("Please enter a date") '<-- remove this line if searching on the fly... (as you enter text)
Exit Sub
End If
DataGridView1.CurrentCell = Nothing
Dim found As Boolean = False
For Each row As DataGridViewRow In DataGridView1.Rows
Row.Visible = Not IsDBNull(row.Cells("DT_Terminit").Value) andalso row.Cells("DT_Terminit").Value =DT
If row.Visible Then found = True
Next
If Not found Then MsgBox("Item not found")

System.NullReferenceException on a ForEach of a datagrid

So all is in the question, I have a datagrid view who's parcoured by a foreach in his rows collection like so dataGridView1.Rows and I get and error of null type in the second if of the for each
Sub DataColumnFirstDouble(ByRef dGridView As DataGridView, ByVal iCol As Integer)
Dim bFirstRow As Boolean = False
Dim sTemp As String = ""
For Each RW As DataGridViewRow In dGridView.Rows
If (bFirstRow) Then
If (RW.Cells(iCol).Value.ToString() = sTemp) Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
sTemp = RW.Cells(iCol).Value.ToString()
bFirstRow = True
Next
End Sub
By the way the Datagrid is populated with 1 entry going
LongString, Number, Number
Hello , 8 , 8
The bug occur when I click on a new row also the function is called on the event of row leave
Need some help
By the way what I try to do is to check when the user enter the name in the longstring space who's a primary unique key in a database but It seems I can't find anythings to handle it by vb so I try to parse it every times he leave the rows to check if there's any double
It isn't clear where the error is, you should debug to figure out which variable exactly is null. So I'll assume it's RW.Cells(iCol).Value.
If there's no value in the cell, it might be null. This mean ToString won't work.
If (bFirstRow) Then
If RW.Cells(iCol).Value IsNot Nothing AndAlso RW.Cells(iCol).Value.ToString() = sTemp Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
You could even check if RW.Cells(iCol) exists, maybe it's trying to fetch the data in a cell that doesn't exists in the row.

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?