I have a DataGridView bound to a BindingSource. I then have a Button to add a new record:
Private Sub btnNew_Click(sender As Object, e As EventArgs) Handles btnNew.Click
_bsStaff.AddNew()
End Sub
This does create a new row, also following it with the "next new/blank" row. This works fine, except if I immediately press my Delete button to try and remove this newly added row:
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
If MessageBox.Show("Delete staff member record?", "Confirm", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
_bsStaff.RemoveCurrent()
End If
End Sub
This removes the new row, but also the one before it!
I tried adding a line before RemoveCurrent, _bsStaff.EndEdit()
and also If _bsStaff.Position + 1 = _bsStaff.Count Then
, but the behaviour persists.
Could someone explain this behaviour and offer a solution?
Added: I thought I had it beat with this code, checking the row state:
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
Dim state = CType(_bsStaff.Current, DataRowView).Row.RowState
Select Case state
Case DataRowState.Added
_bsStaff.RemoveCurrent()
Case DataRowState.Deleted
MessageBox.Show("Row already deleted.", "Delete")
Case DataRowState.Detached
_bsStaff.CancelEdit()
Case DataRowState.Modified
If MessageBox.Show("Delete staff member record?", "Confirm", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
_bsStaff.RemoveCurrent()
End If
Case DataRowState.Unchanged
If _bsStaff.Position + 1 > _bsStaff.Count Then
'do nothing, the new row
ElseIf MessageBox.Show("Delete staff member record?", "Confirm", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
_bsStaff.RemoveCurrent()
End If
Case Else
'do nothing
End Select
End Sub
However, looking at the screenshot,
when I click into the new row, and then click my button, it is in an Unchanged state, but it is the previous row that has the current record pointer (and that the Unchanged state probably refers to), it is this row that will be deleted.
Essentially, I think I need a way to detect that the new row has just been clicked into, but nothing has been typed, so that I can abandon the attempt to delete.
In the meantime, and for comparison and comment (and criticism), I'll post my second, improved, solution here.
Here is my current full code block for the Delete method:
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
If _bsStaff.Current Is Nothing Then
Exit Sub 'nothing to consider deleting
End If
Dim currentRow = CType(_bsStaff.Current, DataRowView).Row
Dim sMemberMessage As String
Dim state = currentRow.RowState
Select Case state
Case DataRowState.Added
'newly added, just remove it
_bsStaff.RemoveCurrent()
Case DataRowState.Deleted
MessageBox.Show("Row already deleted.", "Delete")
Case DataRowState.Detached
_bsStaff.CancelEdit()
Case DataRowState.Modified, DataRowState.Unchanged
If dgvStaff.SelectedCells.Count > 0 AndAlso _
dgvStaff.SelectedCells(0).RowIndex = dgvStaff.NewRowIndex Then
'a new, blank, row, is attempted to be deleted
'(the current row is the one before this)
_bsStaff.CancelEdit()
Exit Sub
End If
sMemberMessage = String.Format("Delete record ({0} {1} {2}) ?", _
_bsStaff.Current("StaffID"), _bsStaff.Current("FirstName"), _bsStaff.Current("LastName"))
If MessageBox.Show(sMemberMessage, "Confirm", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
_bsStaff.RemoveCurrent()
End If
Case Else
'do nothing
End Select
End Sub
The key component is here:
Case DataRowState.Modified, DataRowState.Unchanged
If dgvStaff.SelectedCells.Count > 0 AndAlso _
dgvStaff.SelectedCells(0).RowIndex = dgvStaff.NewRowIndex Then
'a new, blank, row, is attempted to be deleted
'(the current row is the one before this)
_bsStaff.CancelEdit()
Exit Sub
End If
Looking at the screenshot in my question, although the current row is the one just above the new row, there is still a SelectedCell in the new row. With dgvStaff.SelectedCells(0).RowIndex = dgvStaff.NewRowIndex
I am confirming that this cell is in the new (blank) row. Now this will only be the case if the user has clicked into this new row, so it is in an Unchanged
state, and immediately pressed the Delete button, which is the exact situation I am trying to detect. If they had typed anything in this new row, then it would no longer be the new row (the test condition would not be met), nor would it be in an unchanged state. In these circumstances, the earlier cases would already have caused the row to be abandoned.
It is a little clumsy (I'm still hoping for an improvement upon this) but it is also a very specific circumstance that I am trying to capture.