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

DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする を拡張し、隣だけではなく任意のセルにフォーカスが移動できるようにしてみました。

考え方は、次の通りです。


Enter キーが押されたときにイベント EnterKeyPressed を発生させるように拡張したクラスは、次のようになります。

/// <summary>
/// Enter キーが押されたときにイベントを発生させるように拡張した
/// <see cref="DataGridView"/> クラス。
/// </summary>
public class MyDataGridView : DataGridView
{
    // DataGridView で Enter キーが押されたときに発生させるイベント。
    public event EventHandler EnterKeyPressed;

    // 以下のプログラムの基本部分は、
    // "DataGridViewでEnterキーを押すと隣のセルにフォーカスが移動されるようにする"
    // (https://dobon.net/vb/dotnet/datagridview/enterkeymoveright.html) から
    // 使わせていただきました。
    [System.Security.Permissions.UIPermission(
        System.Security.Permissions.SecurityAction.Demand,
        Window = System.Security.Permissions.UIPermissionWindow.AllWindows)]
    protected override bool ProcessDialogKey(Keys keyData)
    {
        // Enterキーが押された時は、EnterKeyPressed イベントを発生させる。
        if ((keyData & Keys.KeyCode) == Keys.Enter)
        {
            EnterKeyPressed?.Invoke(this, EventArgs.Empty);
        }
        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キーが押された時は、EnterKeyPressed イベントを発生させる。
        if (e.KeyCode == Keys.Enter)
        {
            EnterKeyPressed?.Invoke(this, EventArgs.Empty);
        }
        return base.ProcessDataGridViewKey(e);
    }
}


フォームがロードされたとき、拡張した DataGridView をフォームに追加し設定を行う部分を、次に示します。

private void Form1_Load(object sender, EventArgs e)
{
    // MyDataGridView をフォームに追加する。
    MyDataGridView myDgv = new MyDataGridView();
    Controls.Add(myDgv);

    // 追加した MyDataGridView をフォーム全体に表示し、列と行を追加する。
    myDgv.Dock = DockStyle.Fill;
    myDgv.Columns.Add("column1", "列 1");
    myDgv.Columns.Add("column2", "列 2");
    myDgv.Columns.Add("column3", "列 3");
    myDgv.Rows.Add();

    // Enter キーが押されたら MyDgvEnterKeyPressed を呼び出す。
    myDgv.EnterKeyPressed += MyDgvEnterKeyPressed;
}


Enter キーが押されたときに呼び出されるイベントハンドラです。BeginInvoke で指定した内容は、呼ばれた時点ですぐに実行されるのではなく、この一連の処理のあと実行されることになります。この呼び出しに続く処理で、フォーカスはどこか別のセルに移動されるかもしれません。しかし、その後で実行される BeginInvoke のアクションにより、ここで設定した位置にさらに移動します。

private void MyDgvEnterKeyPressed(object sender, EventArgs e)
{
    // CurrentCell が設定されておらず null なら、そのまま戻る。
    MyDataGridView myDgv = (MyDataGridView)sender;
    DataGridViewCell currCell = myDgv.CurrentCell;
    if (currCell == null)
    {
        return;
    }

    // 次にフォーカスが移動するセルを決める。ここでは右斜め下に移動させる。
    int nextColumnIndex = (currCell.ColumnIndex + 1) % myDgv.ColumnCount;
    int nextRowIndex = (currCell.RowIndex + 1) % myDgv.RowCount;
    DataGridViewCell nextCell = myDgv[nextColumnIndex, nextRowIndex];

    // 次に移動するセルを BeginInvoke() で設定する。
    Action setCurrentCellAction = new Action(() => myDgv.CurrentCell = nextCell);
    BeginInvoke(setCurrentCellAction);
}