aphid
aphid

Reputation: 1163

DataGridView: EditOnEnter selection mode allowing row deletion

By default, a DataGridView is set to EditOnKeystrokeOrF2 edit mode. This means two or three clicks (spaced further apart than the user's double click interval) are required to change the value of a combobox in this view. As this is rather strange for a UI object, you would tend to think the control doesn't work.

Fortunately, you can change the selection mode to EditOnEnter. This will immediately select a cell when clicking on it, not first select the row, reducing the amount of clicks by 1. However, DataGridViews are implemented somewhat strangely. There is a '-1th' cell that is not manually selectable in each row.

When this '-1th' cell is selected, in the normal selection mode the row is selected, but in the "EditOnEnter" mode the 1st cell in the row is selected instead. If the DataGridView is set to enable row deletion using the "Del" key, then using EditOnEnter makes it impossible to use this functionality.

How do I get both to work? I.e.: I don't have a view where the user can have click up to 6 times (users tend to click more rapidly when they have to do so a lot of times) to open a box, while at the same time allowing row selection using the special -1th column?

Upvotes: 1

Views: 254

Answers (1)

aphid
aphid

Reputation: 1163

One would need to programmatically toggle between both edit modes when any cell in the row is clicked. However, the CellClick event fires too late: after the row is already selected. Naively just toggling the EditMode would mean that the first click on the row selection box doesn't work, while the second would, which would appear as buggy behaviour.

The trick is to do much more manually. The following event handler, when attached to the CellClick event, will resolve almost all issues.

Private Sub CellSelect(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles myDataGridView.CellClick
    Dim dgv As DataGridView = CType(sender, DataGridView)
    If dgv.Rows.Count = 0 Then 
        Return 
    End If 
    Dim rowToSelect As Integer = e.RowIndex
    Dim columnToSelect As Integer = e.ColumnIndex
    If e.RowIndex = -1 Then
        rowToSelect = 0
    End If
    If rowToSelect >= dgv.Rows.Count Then
        rowToSelect = 0
    End If
    If columnToSelect = -1 Then
        dgv.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2
        dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect
        dgv.CurrentCell = Nothing
        dgv.Rows(rowToSelect).Selected = True
    Else
        If columnToSelect >= dgv.Rows(rowToSelect).Cells.Count Then
            columnToSelect = 0
        End If
        dgv.EditMode = DataGridViewEditMode.EditOnEnter
        dgv.SelectionMode = DataGridViewSelectionMode.CellSelect
        dgv.Rows(rowToSelect).Cells(columnToSelect).Selected = True
    End If
End Sub

It works by unsetting the selected cell, then setting the selected row programmatically. As the EditMode was changed beforehand, it will select the entire row, not just the first cell, even the first time that the row-selection box is clicked.

There are also a whole bunch of edge cases where a user that clicks quickly enough can create click events on cells that do not exist. So we assume those clicks are on the cell [0,0] so at least our application won't blow up.

This isn't a perfect solution (yet). With this solution: A small graphical glitch remains; for about one frame the DataGridView will flicker between edit modes, very briefly appearing as though the row is selected.

Upvotes: 1

Related Questions