When the last row in a DataGridView is selected, a value from the previous row is returned instead of from the selected row - vb.net

I have a DataGridView on a form which is populated by a dataset. Everything works except one thing. In the first column I have id numbers. The user clicks on some row, and the id number from the column is taken to be deleted from the db. Every id is taking correctly except the last row - it is a new row, as you know, because the user can create new records in the database. Anyhow, if the user makes a mistake and selects this row, my code shown below somehow gets the id number from the previous row. I don't know how to avoid that issue. I am taking it using this code:
dgv.CurrentRow.Cells(0).Value
Edit:
i've added code i am using to better understand the situation:
Form Load event:
Private Sub FrmNewRodzaj_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim del As DelegateGridRefresh = New DelegateGridRefresh(AddressOf FillGrid)
Dim del2 As DelegateGridRefresh = New DelegateGridRefresh(AddressOf AlignGrid)
del = [Delegate].Combine(del, del2)
AddHandler EventGridRefresh, AddressOf del.Invoke
del.Invoke()
End Sub
Fill Grid method:
Private Sub FillGrid()
NewRodzaj = New MachineRodzaj()
dgv.DataSource = NewRodzaj.GetRodzaje.Tables(0)
End Sub
GetRodzaje method:
Public Function GetRodzaje() As DataSet
Dim con As New SqlConnection(strcon)
Dim cmd As New SqlCommand("Select * from tbMachRodzajList", con)
con.Open()
GetRodzajeDataAdapter = New SqlDataAdapter(cmd)
GetRodzajeDataAdapter.Fill(GetRodzajeDataSet, "trial1")
Return GetRodzajeDataSet
End Function
AlignGrid method:
Private Sub AlignGrid()
dgv.RowsDefaultCellStyle.BackColor = Color.SkyBlue 'LightSkyBlue
dgv.AlternatingRowsDefaultCellStyle.BackColor = Color.LightBlue
dgv.ColumnHeadersBorderStyle = DataGridViewCellBorderStyle.None
dgv.AllowUserToAddRows = True
dgv.DefaultCellStyle.Font = New Font("Tahoma", 9)
Me.dgv.DefaultCellStyle.SelectionForeColor = Color.Red
Me.dgv.DefaultCellStyle.SelectionBackColor = Color.Yellow
Me.dgv.RowHeadersVisible = False
Dim column0 As DataGridViewColumn = dgv.Columns(0)
column0.Visible = False
Dim ColNazwa As DataGridViewColumn = dgv.Columns(1)
ColNazwa.HeaderText = "Nazwa"
ColNazwa.[ReadOnly] = False
Dim ColOpis As DataGridViewColumn = dgv.Columns(2)
ColOpis.HeaderText = "Opis"
ColOpis.[ReadOnly] = False
Dim column3 As DataGridViewColumn = dgv.Columns(3)
column3.Visible = False
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
Dim dgvColumnHeaderStyle As New DataGridViewCellStyle()
dgvColumnHeaderStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
dgv.ColumnHeadersDefaultCellStyle = dgvColumnHeaderStyle
'You cannot change the column and row header colours without disabling visual styles:
dgv.EnableHeadersVisualStyles = False
' Set the row and column header styles.
dgv.ColumnHeadersDefaultCellStyle.ForeColor = Color.WhiteSmoke
dgv.ColumnHeadersDefaultCellStyle.BackColor = Color.Firebrick
dgv.ColumnHeadersDefaultCellStyle.Font = New Font("Tahoma", 14)
End Sub
button method to save/update data:
Private Sub btnSave_Click(sender As System.Object, e As System.EventArgs) Handles btnZapisz.Click
NewRodzaj.MakeChanges()
RaiseEvent EventGridRefresh()
End Sub
MakeChanges method:
Public Sub MakeChanges()
MachineRodzajDAO.GetRodzajeMakeChanges()
End Sub
GetRodzajeMakeChanges method:
Public Sub GetRodzajeMakeChanges()
If Not GetRodzajeDataSet.HasChanges Then
MessageBox.Show("No changes no need to update", "Informacja", MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
Dim cmdbuilder As New SqlCommandBuilder(GetRodzajeDataAdapter)
Dim i As Integer
Try
i = GetRodzajeDataAdapter.Update(GetRodzajeDataSet, "trial1")
MsgBox("Updated" & i & " records")
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
End Sub
so the one is missing and i am fighting with is delete button after user select row to be deleted from db and click delete button, if he select newRow then message should appear - you selected wrong row. The id values are placed within column(0) when i use CurrentRow.Cells(0).Value if user click newRow then id is id of before row so i cannot just make check if value is nothing and also IsNewRow not working.
Private Sub btnDelete_Click(sender As System.Object, e As System.EventArgs) Handles btnUsun.Click
End Sub
Hope now will be clear enough

actually isNewRow works great
put it on Event dgv.CellClick for example
If dgv.CurrentRow.IsNewRow Then
'Cancel your code
Else
'Execute your code
End If
Edit: then check the row index like
dgv.NewRowIndex
that will always be the NewRowIndex
so if a user clicks a row or NewRow that row will become CurrentRow
you could then check stuff like
If dgv.CurrentRow.Index = dgv.NewRowIndex - 1 Then
'User clicked NewRow but CurrentRow is the one before the NewRow
End If
Edit: actually this is pretty straight forward
but you have to know what is happening on your DGV.
1.
user clicks NewRow and the ClickedCell just gets selected then u get the correct RowIndex with
dgv.SelectedCells(0).RowIndex
which is the same as
BenutzerDataGridView.NewRowIndex
and CurrentRow.Index will always be -1
User clicks NewRow and start typing. Now NewRow moves one Row down and the Row which is being edited becomes CurrentRow.
that's why i added the above to always ensure that it is not the NewRow
If dgv.CurrentRow.Index = dgv.NewRowIndex - 1 Then
this should actually be enough to do what you want ^^
last EDIT:
If dgv.SelectedCells(0).RowIndex = dgv.NewRowIndex Then
MsgBox("wrong row")
End If
or this way
If dgv.Rows(dgv.SelectedCells(0).RowIndex).IsNewRow Then
MsgBox("wrong row")
End If
i'm glad u got it sorted out ^^

Related

ctrl F in DataGridView

I'm trying to implement an equivalent to a ctrl+F function in my project. I want it to work like in an excel where the cursor points at the matching string in any cell. It can also work as a filter that only show the rows with the matching string.
EDIT 1 : Here is what i tried when using #Gabriel Stancu 's method :
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
'Dim search As New OleDbCommand
'Dim da As OleDbDataAdapter
Dim ds As New DataSet
Dim dt As New DataTable
Dim dgv As DataGridView
Dim searchedValue As String
frmPrinc.dgv.DataSource = dt.DefaultView
searchedValue = txtBoxName.Text
MsgBox(searchedValue) 'Displayed
For Each row As DataGridViewRow In frmPrinc.dgv.Rows
MsgBox("yes") 'Not displayed
For Each cell As DataGridViewCell In row.Cells
MsgBox("yes2") 'Not displayed
If cell.Value IsNot DBNull.Value Then
MsgBox("yes3") 'Not displayed
If cell.Value.ToString().Equals(searchedValue) Then
cell.Selected = True
MsgBox(cell.Selected)
Exit Sub
End If
End If
Next
Next
End Sub
this just cleared my DataGridView display
EDIT 2 : Here's what i'm currently working on using #jmcilhinney 's method :
Private Sub btnSearch_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSearch.Click
Dim myBindingSource As New BindingSource
Dim myDataTable As New DataTable
Dim myDataGridView As New DataGridView
myBindingSource.DataSource = myDataTable
myDataGridView.DataSource = myBindingSource
Dim myValue As String
myValue = txtBoxName.Text
MsgBox(myValue)
myDataTable.Columns.Add(New DataColumn("NAME", GetType(String)))
myBindingSource.DataSource = myDataTable
myBindingSource.Position = myBindingSource.Find("NAME", myValue) 'Running fails on this line
'myBindingSource.Filter = $"MyColumn LIKE '%{myValue}% OR MyOtherColumn LIKE '%{myValue}%'"
Dim sourceRows = myBindingSource.Cast(Of DataRowView)().
Where(Function(drv) CStr(drv("NOM")).Contains(myValue)).
ToArray()
For Each gridRow As DataGridViewRow In myDataGridView.Rows
gridRow.Selected = sourceRows.Contains(DirectCast(gridRow.DataBoundItem, DataRowView))
Next
End Sub
This above is still work in progress but i'm a bit stuck getting a
System.ArgumentException : 'DataMember property' NAME 'could not be found in the DataSource.'
If you already have a populated grid then the code to search or filter has nothing at all to do with your database. What you should be doing is populating a DataTable, using either a data adapter or a data reader, binding that to a BindingSource and then binding that to your DataGridView, e.g.
myBindingSource.DataSource = myDataTable
myDataGridView.DataSource = myBindingSource
Searching or filtering is then using the BindingSource. To select the first record with a specific value in a specific column:
myBindingSource.Position = myBindingSource.Find("MyColumn", myValue)
To filter out rows that don't contain a partial value in any column:
myBindingSource.Filter = $"MyColumn LIKE '%{myValue}% OR MyOtherColumn LIKE '%{myValue}%'"
To select each row in the grid that matches those conditions without actually filtering:
Dim sourceRows = myBindingSource.Cast(Of DataRowView)().
Where(Function(drv) CStr(drv("MyColumn")).Contains(myValue)).
ToArray()
For Each gridRow As DataGridViewRow In myDataGridView.Rows
gridRow.Selected = sourceRows.Contains(DirectCast(gridRow.DataBoundItem, DataRowView))
Next
Okay thanks to #Gabriel Stancu this worked for me :
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
Dim da As OleDbDataAdapter
Dim ds As New DataSet
Dim dt As New DataTable
Dim dgv As New DataGridView
ds.Tables.Add(dt)
da = New OleDbDataAdapter("*", getConnexion) ' * here are my columns name
Dim cmdBuilder As New OleDbCommandBuilder(da)
cmdBuilder.QuotePrefix = "["
cmdBuilder.QuoteSuffix = "]"
da.Fill(dt) 'here is what i forgot
dgv.DataSource = dt.DefaultView
Dim searchedValue As String
frmPrinc.dgv.DataSource = dt.DefaultView
searchedValue = txtBoxName.Text
'MsgBox(searchedValue) 'breakpoint to make sure the input string was correct
For Each row As DataGridViewRow In frmPrinc.dgv.Rows
For Each cell As DataGridViewCell In row.Cells
If cell.Value IsNot DBNull.Value And cell.Value IsNot Nothing Then 'you also need to check for the "Nothing" value
If cell.Value.ToString().Equals(searchedValue) Then
frmPrinc.dgv.SelectionMode = DataGridViewSelectionMode.CellSelect 'add this to only select a cell, not the entire row
cell.Selected = True
Exit Sub
End If
End If
Next
Next
End Sub
As jmcilhinney specified in the comments, your code has nothing to do with what you want to achieve. A first approach that comes to my mind (might not be the most efficient) would be to go row by row and column by column. Something like:
Private Sub SearchCellValue(ByVal searchedValue As String)
For Each row As DataGridViewRow In dgvSample.Rows
For Each cell As DataGridViewCell In row.Cells
If cell.Value IsNot DBNull.Value And cell.Value IsNot Nothing Then 'you also need to check for the "Nothing" value
If cell.Value.ToString().Equals(searchedValue) Then
dgvSample.SelectionMode = DataGridViewSelectionMode.CellSelect 'add this to only select a cell, not the entire row
cell.Selected = True
Exit Sub
End If
End If
Next
Next
End Sub
You could also search in the DataTable which holds the data for the DataGridView, get the corresponding indexes (row and column) and then select the corresponding cell in the DataGridView (as it is not quite the best practice to implement code logic directly on the UI which should be separated). Anyway, both approaches seem faster than looking directly in the database, as your approach suggests you intend to do.
You could also make this a Boolean Function and return a value (True if you found the value, False otherwise). This is just a sample code to guide you. Before jumping into complex stuff, make sure you read some documentation or at least follow some tutorials step by step.

Textbox not refreshing

Dim VoucherOpenConnection As New OleDbConnection
' VoucherOpenConnection = New OleDbConnection
VoucherOpenConnection.ConnectionString = "My Connection String"
Dim VoucherString As String = "My Query"
Dim DAVoucherString As New OleDbDataAdapter(VoucherString, VoucherOpenConnection)
Dim DTVoucherString As New DataTable
DAVoucherString.Fill(DTVoucherString)
If DTVoucherString.Rows.Count <> 0 Then
cmbCategory.Text = DTVoucherString.Rows(0).Item(8).ToString
txtDetails.Text = DTVoucherString.Rows(0).Item(2).ToString
txtshop.Text = DTVoucherString.Rows(0).Item(3).ToString
txtAmount.Text = DTVoucherString.Rows(0).Item(4).ToString
txtRemarks.Text = DTVoucherString.Rows(0).Item(5).ToString
txtInvoiceNum.Text = DTVoucherString.Rows(0).Item(11).ToString
txtCashAmt.Text = DTVoucherString.Rows(0).Item(6).ToString
Me.Refresh()
Else
MsgBox("No valid record could be found(Cash)!!")
End If
I have the above code inside a sub procedure and call it from another form. When the sub is called the first time, all the textboxes display the correct values. But when I try again, the values do not update. Putting a breakpoint in the sub reveals that the code is working correctly as hovering the mouse over the textboxes shows the correct values.
I have already tried the following methods to no avail:
Me.Refresh
Me.Update
Textbox.update/refresh
This is in VB.NET 2019.
Edit:Code in the calling form:
Private Sub DGVTotalReport_CellMouseDoubleClick(sender As Object, e As
DataGridViewCellMouseEventArgs) Handles
DGVTotalReport.CellMouseDoubleClick
Dim ExpForm As New ExpenseEntry
My.Settings.TranCodeExpOpen =
DGVTotalReport.Rows(e.RowIndex).Cells(8).Value
If My.Settings.ExpenseForm = False Then
ExpForm.Show()
ExpForm.OpenVoucher()
My.Settings.ExpenseForm = True
Else
My.Settings.ExpenseForm = True
ExpForm.Activate()
ExpForm.OpenVoucher()
ExpForm.Refresh()
End If
End Sub

DataGridView loses cell formatting from DataTable.AcceptChanges

VB2010. I have researched this issue and cannot seem to find a reason for it or a workaround. What I have is a DataGridView that is bound to a DataTable. I allow the user to select Edit mode which turns ON/OFF the ReadOnly property. Once ReadMode=True I make sure to set the DataTable to AcceptChanges. When this property is set all my cell formatting disappears.
I do this on form load:
Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
dgv.DataSource = Nothing
dgv.DataSource = GetTripData()
dgv.AutoResizeColumns()
dgv.ClearSelection()
dgv.ReadOnly = True
End Sub
Then the user can click on a menu item to go into Edit Mode:
Private Sub mnuEditMode_Click(sender As System.Object, e As System.EventArgs) Handles mnuEditMode.Click
If mnuEditMode.Checked Then
dgv.ReadOnly = False
dgv.AllowUserToAddRows = True
dgv.AllowUserToDeleteRows = True
Else
dgv.ReadOnly = True
dgv.AllowUserToAddRows = False
dgv.AllowUserToDeleteRows = False
'accept all changes. if we dont do this any row that is deleted will still exist in the DataTable.
Dim dt As DataTable = CType(dgv.DataSource, DataTable)
If dt IsNot Nothing Then
dt.AcceptChanges() 'note: this causes custom cell font to be cleared
End If
End If
End Sub
Once in edit mode they can dictate which cells to change. Two cells they put in the list to change are treated a such:
'update the proper cells via the DataGridView
dgv.Rows(2).Cells(5).Value = "HOME"
dgv.Rows(2).Cells(6).Value = 10
'bold the cell's font in the DataGridView
Dim styleUpdated As New DataGridViewCellStyle
styleUpdated.Font = New Font(dgv.Font, FontStyle.Bold)
dgv.Rows(2).Cells(6).Style = styleUpdated
dgv.Rows(2).Cells(6).Style = styleUpdated
'refresh the DGV
dgv.Refresh()
This works! I can see the changes in the DGV. Now they are done with editing the data so they click on the menu item to set Edit Mode Off and that sets dgv.ReadOnly=True and I also set dt.AcceptChanges. This last method AcceptChanges clears all the bold fonts on modified cells.
Is this expected behavior? If so what suggestions are there to keep my edited cell formatting?
This isn't really an answer but I want to post a significant piece of code so I'm posting it as an answer. I just tested the following code and it worked for me, in that the bold text remained as the two Buttons were clicked.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim table As New DataTable
With table.Columns
.Add("Id", GetType(Integer))
.Add("Name", GetType(String))
.Add("Age", GetType(Integer))
End With
With table.Rows
.Add(1, "Mary", 20)
.Add(2, "Paul", 30)
.Add(3, "Peter", 40)
End With
DataGridView1.DataSource = table
Dim style = DataGridView1.Rows(1).Cells(1).Style
style.Font = New Font(DataGridView1.Font, FontStyle.Bold)
DataGridView1.Rows(1).Cells(1).Style = style
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
With DataGridView1
.ReadOnly = True
.AllowUserToAddRows = False
.AllowUserToDeleteRows = False
End With
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
With DataGridView1
.ReadOnly = False
.AllowUserToAddRows = True
.AllowUserToDeleteRows = True
End With
End Sub
End Class
I'd suggest that you give that code a go and, if it works for you, you know that there's something else going on in your original project. You can then modify that test project slowly to make it more and more like your existing project and you should then be able to see where this functionality breaks.
I looked some more and I think the cell formatting clearing is expected behavior. So I came up with a small routine that will save each cell's formatting and then re-apply it after the AcceptChanges. Note that my DataTable is small so you may get a performance hit if you have a large dataset. Please provide any feedback if I have missed something:
'updated routine to implement AcceptChanges
'dt.AcceptChanges() 'note: this causes custom cell font to be cleared
DgvAcceptChanges(dgvMain)
''' <summary>
''' this routine will take a DataGridView and save the style for each cell, then it will take it's DataTable source and accept any
''' changes, then it will re-apply the style font to each DataGridView cell. this is required since DataTable.AcceptChanges will
''' clear any DataGridView cell formatting.
''' </summary>
''' <param name="dgv">DataGridView object</param>
''' <remarks>Could be extended to do other things like cell ReadOnly status or cell BackColor.</remarks>
Public Sub DgvAcceptChanges(dgv As DataGridView)
Dim dt As DataTable = CType(dgv.DataSource, DataTable)
If dt IsNot Nothing Then
'save the DataGridView's cell style font to an array
Dim cellStyle(dgv.Rows.Count - 1, dgv.Columns.Count - 1) As DataGridViewCellStyle
For r As Integer = 0 To dgv.Rows.Count - 1
'the DataGridViewRow.IsNewRow Property = Gets a value indicating whether the row is the row for new records.
'Remarks: Because the row for new records is in the Rows collection, use the IsNewRow property to determine whether a row
'is the row for new records or is a populated row. A row stops being the new row when data entry into the row begins.
If Not dgv.Rows(r).IsNewRow Then
For c As Integer = 0 To dgv.Columns.Count - 1
cellStyle(r, c) = dgv.Rows(r).Cells(c).Style
Next c
End If
Next r
'this causes custom cell font to be cleared in the DataGridView
dt.AcceptChanges()
're-apply the DataGridView's cell style font from an array
For r As Integer = 0 To dgv.Rows.Count - 1
If Not dgv.Rows(r).IsNewRow Then
For c As Integer = 0 To dgv.Columns.Count - 1
dgv.Rows(r).Cells(c).Style.Font = cellStyle(r, c).Font
Next c
End If
Next r
End If
End Sub

DataGridView is not showing first row after removing other rows

I am having a problem that I have been debugging for some days.
Some context, I have an application where I store the data (in the following code a list of class Expediente) in xml files using serialization. For displaying the data I deserialize it and then I create a datatable which I use as the datasource for the datagrid. I added a datagridcheckbox column to check the ones to delete.
In the datagrid I have a toolstrip button that when clicked it removes the checked -or checked in edit mode thus the line CType(dgvr.Cells(0).GetEditedFormattedValue(dgvr.Index, DataGridViewDataErrorContexts.Commit), Boolean) = True- elements from the datasource and persists the datasource to an xml.
The problem is that when deserializing the xml and loading it again to a datatable and binding the datagrid datasource to it, it removes the first row. If I close the application and open it, the first row appears.
I have debuged and in the datatable the correct numbers of rows appear. Moreover, I have narrowed the problem to the binding navigator, when it sets its binding source to the datable there the first row of the datagrid disappears.
I paste a simplified version of the code, I can provide more if needed.
Note that if in LoadGridExpedientes() I comment the lines
navExpedientes.BindingSource = Nothing
navExpedientes.BindingSource = bs
The first row doesn't disappear but obviously the counter of the binding navigator does not update.
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim chk As New DataGridViewCheckBoxColumn()
grdExpedientes.Columns.Add(chk)
chk.HeaderText = ""
chk.Name = "chk"
'fills a datatable from an xml, it works ok, it fills it with the correct amount of rows
Dim dt As DataTable = Sistema.getInstance.getDataExpedienteForGrid()
Dim bs As New BindingSource
bs.DataSource = dt
grdExpedientes.DataSource = bs
navExpedientes.BindingSource = bs
For i As Integer = 0 To grdExpedientes.Rows.Count - 2
grdExpedientes.Rows(i).Cells(0).Value = True
Next
End Sub
Private Sub LoadGridExpedientes()
grdExpedientes.DataSource = Nothing
navExpedientes.BindingSource = Nothing
grdExpedientes.Columns.Clear()
grdExpedientes.Rows.Clear()
'This is to know if there is already the checkbox column
If Not (grdExpedientes.Columns.Count > 0 AndAlso grdExpedientes.Columns(0).Name = "chk") Then
Dim chk As New DataGridViewCheckBoxColumn()
grdExpedientes.Columns.Add(chk)
chk.HeaderText = ""
chk.Name = "chk"
End If
Dim dt As DataTable = Sistema.getInstance.getDataExpedienteForGrid()
Dim bs As New BindingSource
bs.DataSource = dt
grdExpedientes.DataSource = bs
navExpedientes.BindingSource = bs
End Sub
Private Sub navExpedientesDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles navExpedientesDelete.Click
For i As Integer = 0 To grdExpedientes.Rows.Count - 2
Dim dgvr As DataGridViewRow = grdExpedientes.Rows(i)
If CType(dgvr.Cells(0).Value, Boolean) = True Or _
CType(dgvr.Cells(0).GetEditedFormattedValue(dgvr.Index, DataGridViewDataErrorContexts.Commit), Boolean) = True Then
Dim draux As DataGridViewRow = dgvr
Dim expABorrar As Expediente = CType((From elem As Expediente In Sistema.listExpedientes
Where elem.Expediente = CType(draux.Cells("Expediente (Ficha)").Value, String)
Select elem).FirstOrDefault, Expediente)
Sistema.listExpedientes.Remove(expABorrar)
End If
Next
If System.IO.File.Exists(Sistema.pathListExpedientes) Then
System.IO.File.Delete(Sistema.pathListExpedientes)
End If
Dim sw As System.IO.TextWriter = New System.IO.StreamWriter(Sistema.rutaListaExpedientes, 0)
Serializer(Of Expediente).Serialize(Sistema.listExpedientes, sw, New List(Of Type) From {GetType(Movimiento)})
sw.Close()
LoadGridExpedientes()
End Sub
The problem was that I was using the delete toolstrip button that comes with the binding navigator, it seems that when clicked it has 'embedded' that it deletes the row that was selected that by default is the first one.
I created a new toolstrip button in the binding navigator and the problem was solved. I do not know why not updating the binding navigator binding source also avoided the first row from being removed.

Why is gridview.selectedColumns nothing?

I want to run a code like this, but it always jumps over the loop, so I see no line in the console.
That means that selectedColumns is empty. My assumption was that I (or the user) select a cell from a Column and then, selectedColummns are +1. But as it looks, it doesnt work. Then I tried to set proberties of selectionMode to select full columns, but then an exception is thrown:
"System.InvalidOperationException" Additional Information: the SortMode cannot be Automatic, if full Column selection is selected.
I don't know what SortMode is.
For Each col As DataGridViewColumn In datagridview2.SelectedColumns
Console.Write(datagridview2.SelectedColumns.Count)
Console.Write("1")
Next
Any Ideas how to get that the columns into selectedColumns?
Here my code that solved my problem, but I guess it is not the smartest one:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim body As String = ""
Dim myWriter As New StreamWriter("H:\downloads\test.csv", True)
Dim list As List(Of Integer) = New List(Of Integer)
For Each cell As DataGridViewCell In datagridview2.SelectedCells
If list.Contains(cell.ColumnIndex) = False Then
list.Add(cell.ColumnIndex)
End If
Next
For i = 0 To datagridview2.Rows.Count - 1
For ix = 0 To datagridview2.Columns.Count - 1
If list.Contains(ix) Then
If datagridview2.Rows(i).Cells(ix).Value IsNot Nothing Then
body = body + datagridview2.Rows(i).Cells(ix).Value.ToString + ";"
Else
body = body + ";"
End If
End If
Next
myWriter.WriteLine(body)
body = ""
Next
myWriter.Close()
End Sub
You need to do this after the selected changed event has fired.
For example:
Private Sub Mydg_ColSelected(sender As Object, e As SelectionChangedEventArgs) Handles datagridview2.SelectionChanged
For Each col As DataGridViewColumn In datagridview2.SelectedColumns
Console.Write(datagridview2.SelectedColumns.Count)
Console.Write("1")
Next
End Sub
Or if this isn't what you are after, then try handling the ColumnHeaderMouseClick event instead. I'm not sure what technology you are using, e.g Winforms, WPF, silverlight