开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜