I've built an Enter-Firendly DataGridView control, which basically just treats the enter key as the tab key, allowing the user to move quickly between cells just by pressing enter. It's very useful for accounting applications.
Anyway, it works fine when the user just uses the enter key, or the arrow keys, to move between cells. It breaks down however when the user uses the mouse. I get the error: Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function.
Here is my code. Sorry one piece is in VB while the other is in C#. I had packaged the DataGridView extension into a class library, and used c# which is my prefered language, but the consuming application was already written in VB.
First the control:
And now the host application:
Anyway, it works fine when the user just uses the enter key, or the arrow keys, to move between cells. It breaks down however when the user uses the mouse. I get the error: Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function.
Here is my code. Sorry one piece is in VB while the other is in C#. I had packaged the DataGridView extension into a class library, and used c# which is my prefered language, but the consuming application was already written in VB.
First the control:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace EnterFriendlyDataGridView
{
public class DataGridViewEnter : DataGridView
{
public string lastColumn;
public event EventHandler rowEntryComplete;
//This override causes the DataGridView to use the enter key in a similar way as
//the tab key
protected override bool ProcessDialogKey(Keys keyData)
{
Keys key = (keyData & Keys.KeyCode);
if (key == Keys.Enter)
{
return this.ProcessEnterKeyAsTab(keyData);
}
return base.ProcessDialogKey(keyData);
}
public bool ProcessEnterKeyAsTab(Keys keyData)
{
if (base.Columns[base.CurrentCell.ColumnIndex].Name == lastColumn)
{
// raise an event which, when handled, ends edit on the current cell
if (rowEntryComplete != null)
rowEntryComplete(this, null);
return true;
}
else
{
// possibly only do this if balances don't match
return base.ProcessTabKey(keyData);
}
}
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
return this.ProcessEnterKeyAsTab(e.KeyData);
else
return base.ProcessDataGridViewKey(e);
}
public void manualHome()
{
base.ProcessHomeKey(Keys.Home);
}
public void manualTab()
{
base.ProcessTabKey(Keys.Tab);
}
}
}
And now the host application:
#Region "DataGridView methods"
Private Sub dgvSerialNumbers_RowEntryComplete(ByVal sender As Object, ByVal e As EventArgs) Handles dgvSerialNumbers.rowEntryComplete
'end edit mode, which fires the CellEndEdit event
dgvSerialNumbers.BeginEdit(False)
dgvSerialNumbers.EndEdit()
End Sub
Private Sub dgvSerialNumbers_CellClick(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgvSerialNumbers.CellClick
Dim a As Integer = 1
End Sub
Private Sub dgvSerialNumbers_CellEndEdit(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgvSerialNumbers.CellEndEdit
Dim fromSN, toSN As String
If e.ColumnIndex = 0 Then
fromSN = dgvSerialNumbers.Rows(e.RowIndex).Cells(0).Value
If dgvSerialNumbers.Rows(e.RowIndex).Cells(1).Value = "" Then
'Copy the From SN to the ToSN
dgvSerialNumbers.Rows(e.RowIndex).Cells(1).Value = fromSN
dgvSerialNumbers.manualTab()
dgvSerialNumbers.BeginEdit(True)
End If
Else
If dgvSerialNumbers.Rows(e.RowIndex).Cells(1).Value Is Nothing Then Exit Sub
'this is where we interpolate To SN's based on From SN's
fromSN = dgvSerialNumbers.Rows(e.RowIndex).Cells(0).Value
toSN = dgvSerialNumbers.Rows(e.RowIndex).Cells(1).Value
If toSN.Length < fromSN.Length Then
toSN = fromSN.Substring(0, fromSN.Length - toSN.Length) + toSN
dgvSerialNumbers.Rows(e.RowIndex).Cells(1).Value = toSN
End If
dgvSerialNumbers.manualTab()
End If
End Sub
#End Region