disable the default Enter/Return key behavior in a datagridview
In vb.net datagridview the default Enter/Return key 开发者_StackOverflowbehavior is to move to the next row is there a quick and easy way to avoid that.
Any suggestions are welcome
You can try something like this in the gridview key down event
Private Sub DataGridView1_Keydown (...) Handles DataGridView1.KeyDown
If e.KeyCode = Keys.Enter Then
' Your code here
e.SuppressKeyPress = True
End If
End Sub
Another option would be to create a custom grid view control
DataGridView.ProcessDataGridViewKey Method
You can just use keyPress event:
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//You're Code
}
e.Handled = true;
return;
}
I myself, when disabling the Enter key’s default behavior on a DataGridView
, want to be able to achieve a similar effect to setting DataGridView.StandardTab
to true
. Enabling StandardTab
enables the user to more easily navigate between different controls in a form. This makes it behave more like a ListBox
, especially if the DataGridView
only has one column. The default behavior of of the Enter key and the behavior which I would expect from setting a (nonexistent) DataGridView.StandardEnter
key to true
would be to send the key event to containing controls, probably resulting in the Form.AcceptButton
being activated. The proposed methods of setting KeyEventArgs.SuppressKeyPress = true
in DataGridView.KeyDown
or not even firing DataGridView.KeyDown
when the input key is Enter do not enable “standard” Enter key behavior; these methods instead let the Enter key event get swallowed.
The following shows how I have managed to get “Standard” Enter key behavior (including invoking AcceptButton
appropriately) out of a DataGridView. It is ugly because I do not know a better way to run the logic in Control.ProcessDialogKey()
(which is just to call the Parent (the container)’s ProcessDialogKey()
or return false
if there is no Parent) than to copy it into my own derived class. (I essentially need to use the invalid/impossible base.base.ProcessDialogKey()
syntax to work around System.Windows.Forms
’s non-extensibility in a cleaner manner). Because of this, I am forced to use reflection to access the protected Control.ProcessDialogKey()
method of the parent (the container) Control
object when it exists.
DataGridVew.IsInputKey()
returns true
for Keys.Enter
. This enables it to see the Enter key in its DataGridView.OnKeyDown()
method where it eventually calls DataGridView.ProcessEnterKey()
which reacts to the Enter key in different ways based on the setting of DataGridView.EditMode
. But this also disables sending the key event to ProcessDialogKey()
from where normal controls would bubble the Enter key event to their Parents (enabling AcceptButton
to work, for example). Thus, we revert this behavior by overriding IsInputKey()
and now DataGridView.ProcessDialogKey()
will get called when Enter is pressed.
But that is not enough. DataGridView.ProcessDialogKey()
has a hardcoded call to DataGridView.ProcessEnterKey()
and only calls its base Control.ProcessDialogKey()
if ProcessEnterKey()
returns false. At this point, it would seem common sense to override ProcessEnterKey()
with something that would just return false
when we want standard Enter key behavior. But, alas, it is a non-virtual method. Thus, we are forced to override something we can override, DataGridView.ProcessDialogKey()
, and reimplement it while skipping the call to ProcessEnterKey()
. This is where we are also unable to directly call Control.ProcessDialogKey()
and are forced to use reflection to call the parent/container object’s ProcessDialogKey()
method. But once we successfully make that call, we finally have standard Enter behavior and AcceptButton
is accessible even while the DataGridView
has focus!
/// <summary>
/// A DataGridView with a StandardEnter property which behaves
/// like StandardTab.
/// </summary>
class StandardEnterDataGridView
: DataGridView
{
/// <summary>
/// Like StandardTab but for the Enter key.
/// </summary>
[Category("Behavior"), Description("Disable default edit/advance to next row behavior of of the Enter key.")]
public bool StandardEnter { get; set; }
/// <summary>
/// Implement StandardEnter.
/// </summary>
protected override bool IsInputKey(Keys keyData)
{
if (StandardEnter && keyData == Keys.Enter)
// Force this key to be treated like something to pass
// to ProcessDialogKey() (like the Enter key normally
// would be for controls which aren’t DataGridView).
return false;
return base.IsInputKey(keyData);
}
private static MethodInfo _Control_ProcessDialogKey = typeof(Control).GetMethod("ProcessDialogKey", BindingFlags.Instance|BindingFlags.NonPublic);
protected override bool ProcessDialogKey(Keys keyData)
{
if (StandardEnter && keyData == Keys.Enter)
// Copy the default implementation of
// Control.ProcessDialogKey(). Since we can’t access
// the base class (DataGridView)’s base class’s
// implementation directly, and since we cannot
// legally access Control.ProcessDialogKey() on other
// Control object, we are forced to use reflection.
return Parent == null ? false : (bool)_Control_ProcessDialogKey.Invoke(Parent, new object[] {keyData, });
return base.ProcessDialogKey(keyData);
}
}
Override the DataGridView (write your own that inherits from it), and process the OnKeyDown method.
public partial class UserControl1 : DataGridView
{
public UserControl1()
{
InitializeComponent();
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
return;
base.OnKeyDown(e);
}
}
I am adding this foot note to this as I was very interested in this article since it ran close to a different problem I had with the DataGridView. This is that the fact the Enter key takes you to the cell below, preventing a users ability to do simple editing to text in a cell. Having overridden the class and spent much time on this, I finally found the following article: Use Enter to add new line in datagridview cell
If this is your only issue, then to know SHIFT+ENTER works (however unintuitive), might save you a lot of time! Think I will just add a label to the form to remind users.
The accepted solution did not work for me. The code below DID. From http://www.vbforums.com/showthread.php?603242-Block-enter-key-in-datagridview-in-vb-net: (original source unknown)
Public Class clsDataGridView
Inherits System.Windows.Forms.DataGridView
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Return Or keyData = Keys.Tab Then
If CurrentCellAddress.X = ColumnCount - 1 Then
keyData = Keys.Cancel
With msg
.WParam = CType(Keys.Cancel, IntPtr)
End With
Else
keyData = Keys.Tab
With msg
.WParam = CType(Keys.Tab, IntPtr)
End With
End If
End If
If keyData = (Keys.Shift Or Keys.Tab) Then
If CurrentCellAddress.X = 0 Then
keyData = Keys.Cancel
With msg
.WParam = CType(Keys.Cancel, IntPtr)
End With
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Return Or keyData = Keys.Tab Then
If CurrentCellAddress.X = ColumnCount - 1 Then
keyData = Keys.Cancel
Else
keyData = Keys.Tab
End If
End If
If keyData = (Keys.Shift Or Keys.Tab) Then
If CurrentCellAddress.X = 0 Then
keyData = Keys.Cancel
End If
End If
Return MyBase.ProcessDialogKey(keyData)
End Function
End Class
精彩评论