DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする

注意:DataGridViewコントロールは、.NET Framework 2.0で新しく追加されました。

ProcessDialogKeyとProcessDataGridViewKeyメソッドをオーバーライドする方法

MSDNの「DataGridView.ProcessDataGridViewKey Method」に、DataGridViewでEnterキーを押した時に、右矢印キーを押した時と同じ動作を行うようにするコードが紹介されています。ここで紹介されている方法は、DataGridViewクラスの派生クラスを作成し、ProcessDialogKeyとProcessDataGridViewKeyメソッドをオーバーライドして、Enterキーが押された時にProcessRightKeyメソッドを呼び出す方法です。

このMSDNのサンプルを参考して作成した、Enterキーを押すことにより、Tabキーを押した時と同じように、隣のセルにフォーカスが移動するDataGridViewの派生クラスを以下に示します。なお、使用法は、「「○○○クラスの代わりに派生クラスを使用します」の意味は?」を参考にしてください。

ここでは、Tabキーを押した時と同じことをするためにProcessTabKeyメソッドを使用していますが、別の方法もあります。詳しくは、「Enterキーを押した時、まるでTabキーを押したかのように、次のコントロールにフォーカスを移す」をご覧ください。

なおDataGridView.StandardTabプロパティはFalseのままにしておいてください。

VB.NET
コードを隠すコードを選択
Imports System
Imports System.Windows.Forms

''' <summary>
''' Enterキーが押された時に、Tabキーが押されたのと同じ動作をする
''' (現在のセルを隣のセルに移動する)DataGridView
''' </summary>
Public Class DataGridViewEx
    Inherits DataGridView

    <System.Security.Permissions.UIPermission( _
        System.Security.Permissions.SecurityAction.Demand, _
        Window:=System.Security.Permissions.UIPermissionWindow.AllWindows)> _
    Protected Overrides Function ProcessDialogKey( _
            ByVal keyData As Keys) As Boolean
        'Enterキーが押された時は、Tabキーが押されたようにする
        If (keyData And Keys.KeyCode) = Keys.Enter Then
            Return Me.ProcessTabKey(keyData)
        End If
        Return MyBase.ProcessDialogKey(keyData)
    End Function

    <System.Security.Permissions.SecurityPermission( _
        System.Security.Permissions.SecurityAction.Demand, _
        Flags:=System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)> _
    Protected Overrides Function ProcessDataGridViewKey( _
            ByVal e As KeyEventArgs) As Boolean
        'Enterキーが押された時は、Tabキーが押されたようにする
        If e.KeyCode = Keys.Enter Then
            Return Me.ProcessTabKey(e.KeyCode)
        End If
        Return MyBase.ProcessDataGridViewKey(e)
    End Function
End Class
C#
コードを隠すコードを選択
using System;
using System.Windows.Forms;

/// <summary>
/// Enterキーが押された時に、Tabキーが押されたのと同じ動作をする
/// (現在のセルを隣のセルに移動する)DataGridView
/// </summary>
public class DataGridViewEx : DataGridView
{
    [System.Security.Permissions.UIPermission(
        System.Security.Permissions.SecurityAction.Demand,
        Window = System.Security.Permissions.UIPermissionWindow.AllWindows)]
    protected override bool ProcessDialogKey(Keys keyData)
    {
        //Enterキーが押された時は、Tabキーが押されたようにする
        if ((keyData & Keys.KeyCode) == Keys.Enter)
        {
            return this.ProcessTabKey(keyData);
        }
        return base.ProcessDialogKey(keyData);
    }

    [System.Security.Permissions.SecurityPermission(
        System.Security.Permissions.SecurityAction.Demand,
        Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
    protected override bool ProcessDataGridViewKey(KeyEventArgs e)
    {
        //Enterキーが押された時は、Tabキーが押されたようにする
        if (e.KeyCode == Keys.Enter)
        {
            return this.ProcessTabKey(e.KeyCode);
        }
        return base.ProcessDataGridViewKey(e);
    }
}

このクラスは、DataGridViewクラスの代わりに使用します。

注意:新しく作成したクラスを、基のコントロールクラスの代わりに使用するという意味が分からないという方は、こちらをご覧ください。

DataGridViewのイベントを使用する方法

DataGridView: Make Enter Key Move to Next Column - CodeProject」には、KeyDownとCellEndEditイベントを使用する方法が紹介されています。

DataGridViewは、セルが編集できない場合は、Enterキーを押した時にKeyDownイベントが発生します。しかしセルが編集できる場合は発生しませんので、別の方法を考える必要がありますが、残念ながら良い方法がありません。選択肢の一つがCellEndEditイベントですが、Enterキーが押された時以外(マウスでクリックした時など)でも発生し、Enterキーが押されたどうかの判断ができません。よってこの方法は、Enterキー以外で編集を終了させた場合、おかしな動作になってしまう可能性があります。

この方法によるサンプルを示します。なお、DataGridView.EditModeプロパティをEditOnEnterにすると、正常に機能しなくなります。

VB.NET
コードを隠すコードを選択
'DataGridView1のKeyDownイベントハンドラ
Private Sub DataGridView1_KeyDown(sender As Object, _
    e As KeyEventArgs) Handles DataGridView1.KeyDown

    If e.KeyCode = Keys.Enter Then
        Dim dgv As DataGridView = DirectCast(sender, DataGridView)

        '最終行最終列の場合は、何もしない(最終行最終列で
        'Tabキーを送信すると、次のコントロールにフォーカスが移動)
        If (dgv.CurrentCellAddress.X = dgv.ColumnCount - 1) AndAlso _
            (dgv.CurrentCellAddress.Y = dgv.RowCount - 1) Then
            Return
        End If

        'Tabキーを送信する
        SendKeys.Send("{TAB}")
        'フォーカスが下に移動しないようにする
        e.Handled = True
    End If
End Sub

'DataGridView1のCellEndEditイベントハンドラ
Private Sub DataGridView1_CellEndEdit(sender As Object, _
    e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit

    Dim dgv As DataGridView = DirectCast(sender, DataGridView)

    '最終行最終列の場合は、何もしない
    If (e.ColumnIndex = dgv.ColumnCount - 1) AndAlso _
        (e.RowIndex = dgv.RowCount - 1) Then
        Return
    End If

    '最終行以外では、フォーカスを上に移動
    '(最終行以外では、編集後、フォーカスが下に移動するため)
    If e.RowIndex < dgv.RowCount - 1 Then
        SendKeys.Send("{UP}")
    End If
    'Tabキーを送信する
    SendKeys.Send("{TAB}")
End Sub
C#
コードを隠すコードを選択
//DataGridView1のKeyDownイベントハンドラ
private void DataGridView1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter)
    {
        DataGridView dgv = (DataGridView)sender;

        //最終行最終列の場合は、何もしない(最終行最終列で
        //Tabキーを送信すると、次のコントロールにフォーカスが移動)
        if ((dgv.CurrentCellAddress.X == dgv.ColumnCount - 1) &&
            (dgv.CurrentCellAddress.Y == dgv.RowCount - 1))
        {
            return;
        }

        //Tabキーを送信する
        SendKeys.Send("{TAB}");
        //フォーカスが下に移動しないようにする
        e.Handled = true;
    }
}

//DataGridView1のCellEndEditイベントハンドラ
private void DataGridView1_CellEndEdit(
    object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    //最終行最終列の場合は、何もしない
    if ((e.ColumnIndex == dgv.ColumnCount - 1) &&
        (e.RowIndex == dgv.RowCount - 1))
    {
        return;
    }

    //最終行以外では、フォーカスを上に移動
    //(最終行以外では、編集後、フォーカスが下に移動するため)
    if (e.RowIndex < dgv.RowCount - 1)
    {
        SendKeys.Send("{UP}");
    }
    //Tabキーを送信する
    SendKeys.Send("{TAB}");
}
補足:「ENTER key as TAB in datagridview issue in vb.net - Stack Overflow」などには、KeyDown、CellEndEdit、SelectionChangedイベントを使用し、CurrentCellプロパティでフォーカスを移動させる方法が紹介されています。しかしこの方法も同じ問題を抱えており、さらにCurrentCellプロパティでフォーカスを移動させる時、例外InvalidOperationExceptionが発生することがあるようです。
  • 履歴:
  • 2010/6/30 ProcessDialogKeyにUIPermissionAttributeを、ProcessDataGridViewKeyにSecurityPermissionAttributeを付けた。
  • 2013/12/9 SecurityAction.LinkDemandの代わりにSecurityAction.Demandを使うようにした。
  • 2014/10/27 イベントを使用する方法を追加。リンク切れを削除。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。