Thursday, July 3, 2008

Making Enter Key, Move to Next Cell/Column in DataGridView After Cell Edit

This article explains how we can customize the DataGridView control so that when Enter Key is pressed then cursor (current selection) move to next cell / column after Cell Edit.

Level: Intermediate

Knowledge Required:
DataGridView

Description:
By default in DataGridView control, when we press Enter Key to stop the editing in Current Cell, cursor moves to next Row and the current row is saved. This style is adopted from Excel, users working on Excel feel no problem with this. But users who worked in older applications do NOT like this type of editing. What they want is when Enter Key is pressed then Cursor should move to next cell / column. In DataGridView control we need to press TAB key to achieve this.

Now we are going to customize the DataGridView control, so that when User Stop the Editing in Current Cell by pressing Enter Key then cursor should move in next cell / column.

To understand the solution first note the followings,

1) When user presses enter key to stop the Editing, DataGridView CellEndEdit event occurs
2) Then cursor (current selection) moves to next row, on this point SelectionChanged event occurs

To achieve this I have used a logic,

1) When CellEndEdit event occurs, I note the Cell which was Edited
2) Then in SelectionChanged event, I first check if this event is occured after the Editing, then I set the cursor (current selection) in the same row but next column of last edited cell

Here I have created a customized control which is actually inherited from DataGridView control, and have added this functionality.

Public Class DataGridViewEnterMoveNext
Inherits DataGridView

Dim celWasEndEdit As DataGridViewCell
Private _EnterMoveNext As Boolean = True

<System.ComponentModel.DefaultValue(True)> _
Public Property OnEnterKeyMoveNext() As Boolean
Get
Return Me
._EnterMoveNext
End Get
Set
(ByVal value As Boolean)
Me._EnterMoveNext = value
End Set
End Property

Private Sub
DataGridView_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles Me.CellEndEdit
Me.celWasEndEdit = Me(e.ColumnIndex, e.RowIndex)
End Sub

Private Sub
DataGridView_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SelectionChanged
' if Enter Move Next should work andalso
' mouse button was NOT down
' we are checking mouse buttons because if select was changed
' by Mouse then we will NOT do our Enter Move Next

If Me._EnterMoveNext AndAlso MouseButtons = 0 Then
' if selection is changed after Cell Editing
If Me.celWasEndEdit IsNot Nothing AndAlso _
Me.CurrentCell IsNot Nothing Then
' if we are currently in the next line of last edit cell
If Me.CurrentCell.RowIndex = Me.celWasEndEdit.RowIndex + 1 AndAlso _
Me.CurrentCell.ColumnIndex = Me.celWasEndEdit.ColumnIndex Then
Dim iColNew As Integer
Dim iRowNew As Integer
' if we at the last column
If Me.celWasEndEdit.ColumnIndex >= Me.ColumnCount - 1 Then
iColNew = 0 ' move to first column
iRowNew = Me.CurrentCell.RowIndex ' and move to next row
Else ' else it means we are NOT at the last column
' move to next column

iColNew = Me.celWasEndEdit.ColumnIndex + 1
' but row should remain same
iRowNew = Me.celWasEndEdit.RowIndex
End If
Me.CurrentCell = Me(iColNew, iRowNew) ' ok set the current column
End If
End If

Me.celWasEndEdit = Nothing ' reset the cell end edit
End If
End Sub
End Class


Note that I have added a property OnEnterKeyMoveNext if this property is True then our customization will work otherwise NOT.

Limitations:
As you can see when user presses enter key, the row will be first saved in DataGridView control (ultimately the Source of DataGridView is updated), at this point if one or more columns are NOT allowed to have NULL values then our customization will NOT work properly. Since exception will be thrown and the row will be deleted. To overcome this issue we can set the AllowDBNull = False in our DataTable (which is bind with DataGridView) and use the custom validation as discussed in my previous post.

How to add Column/Row Validation Using Typed DataTable

Download Source Code:
DataGridViewEnterAsTab.Zip

See Also:
DataGridView control FAQs and Quick Tips
Paste Text in DataGridView Control (Bound with BindingSource)

12 comments:

Emile Kaselowski said...

Dude, you are my hero for today. I'm also an avid VB.net programmer (2008) developing an inventory-based system. THIS issue has been giving me gray hair for the past week until I came across your solution!

-Emile

Anonymous said...

Hi,

I'm developing an Orders entering program, I came across with your solution (which I needed), I tried to implemented in my programam, without success; what I'm doing is to add a new class in the solution explorer and pasting your code, but as I entering data and click enter, nothing happens, wonder if I'm missing something.

Thank you veru much in advance,

Best regards

Alex.

Arsalan Tamiz said...

Hi Alex,

Try downloading the sample and test it. One more thing, the above source is for the scenario "when user presses enter to end the cell editing". If you press enter when NOT editing a cell the DataGridView will do its default behaviour i.e. will move the focus in next row.

Anonymous said...

Hi Arzalam,

Very kind for answering, I already downloaded you example and works very well, but not in my application; for sure I'm missing something, I added the following portion of code in Public Class Form1:

Private Sub ACM_SUG_PEDIDO_CODIGO_ARTICULODataGridView_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles ACM_SUG_PEDIDO_CODIGO_ARTICULODataGridView.CellContentClick

End Sub

And the DataGridViewEnterMoveNext Class exactly the same as in your example.

Please advise.

Best regards.

Alex
velazqa@hotmail.com

Anonymous said...

Arsalan,

Alex again, nust to comment, I do'nt see the property OnEnterKeyMoveNext, on my Form properties, I am missing something..

Regards.

Alex

Arsalan Tamiz said...

Hi Alex,

Lets try step by step.

First remove the existing control/coding etc. related to my control from your project.

1) Press Ctl+D (Add exsisting Item)
2) Browse up to my sample's folder then select the control file i.e. "NewDataGridView.vb"
3) Rebuild the project, this will add the Control's icon in ToolBar
4) Drag the control from tool bar and put it on form
5) Try some testing first. Add some columns and just test the control whether it is working or NOT.

Make sure you have read the "Limitations" in this article. If still no success then try emailing me the limited source code (NOT the whole project). So I can see what is wrong there.

Good Luck,
Arsalan Tamiz

Anonymous said...

Arsalan,

I followed your instructions and now I can see the class properly and it works partially well, the problem comes when I get to the last column, it is supposed to position in next row first column, instead I'm getting "Invalid Operation Exception", "Current Cell Can't be established on an invincible cell", it stops on:

Me.CurrentCell = Me(iColNew, iRowNew) ' ok set the current column

of the Private Sub DataGridView_SelectionChanged

Many thank in advance.

Best regards.

Alex.

Arsalan Tamiz said...

OK I get it now.

The error is straight forward i.e. your 1st (or any other) column is “invisible”. Means you have set its “Visible” property = False.

In that case you should add some extra checks in the Control’s source code.

Anonymous said...

Arsalan,

I already made some adjusts to your code and it's working very well, the last problem was the hiden columns, many thanks, I am going to stick to your blog in order for me to learn from you.

Thanks again.

Alex.

Umesh said...

,
really thnx man, i din't know after cellendedit, selectionchanged is called, this helped me alot.
God bless U.

Anonymous said...

Hi,

Your post is very valuable to me i have almost cleared my doubt reading your blog. I use C#, can you explain the same solutions using c#. I would be very thankful to you.

Warm Regards,

Andika-Febrianto said...

Thanks for the code, its really help, i changed your event from CellEndEdit to CellLeave so every hit enter cell will move to next column.

Private Sub DataGridView1_CellLeave(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellLeave
Me.celWasEndEdit = DataGridView1.Item(e.ColumnIndex, e.RowIndex)
End Sub