読者です 読者をやめる 読者になる 読者になる

たきるブログ

C#やOracleなどの情報を書いています。

【C#】EnterキーでTabキーを押した時と全く同じフォーカス遷移を行う

EnterキーでTabキーを押した時と同じフォーカス遷移を行いたいという要望は、案外多い。
古いシステムからの名残りだったり、そもそも提案した人が古い人だったりで。
果てはWebシステムでもそれを望むこともあるが、今回はWindows Formsアプリケーションの場合の解決方法を記す。

Enterキーでフォーカス遷移する方法は、難しく考えすぎて意外とハマる。
他のサイトで調べた結果、最適解を導き出した。

参考サイト

Enterキーを押した時、まるでTabキーを押したかのように、次のコントロールにフォーカスを移す: .NET Tips: C#, VB.NET
色々あって全部試したわけではないが、コンポーネント単位に継承するのは非効率。
コメント欄に[たきる]ってなってるのは俺^^;

.NET TIPS:Windowsアプリケーションで[Enter]キーによるフォーカス移動を行うには? - @IT
C# - フォームで [Enter] キーが押された時にフォーカスを遷移させる
SelectNextControlメソッドを利用すると、『自分のオブジェクト配下に存在するコントロールを遷移する』だけであり、Tabキーと全く同じにはならない。

主なハマる点

基本的には、参考サイトにある方法論でも問題ない。
しかし、SplitContainerを利用した途端、『Tabキーを押した時と全く同じ』とはならない。
例えばこんな状態のフォーム内容の場合。(TextBox内の値が、Tabキー押下時に遷移するタブ順)
f:id:metroit:20150625102155p:plain

解決策

これが最も適切に動作すると思う。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// ダイアログ キーを処理します。
        /// </summary>
        /// <param name="keyData">処理するキーを表す Keys 値の 1 つ。</param>
        /// <returns>キーがコントロールによって処理された場合は true。それ以外の場合は false。</returns>
        protected override bool ProcessDialogKey(Keys keyData)
        {
            // Enterキー押下によるフォーカス移動
            if (((keyData & Keys.KeyCode) == Keys.Return) &&
                ((keyData & (Keys.Alt | Keys.Control)) == Keys.None))
            {
                this.MoveNextControl();
                return true;
            }

            return base.ProcessDialogKey(keyData);
        }

        /// <summary>
        /// 次のコントロールをアクティブにします。
        /// </summary>
        /// <param name="forward">タブオーダー内を前方に移動する場合はtrue。後方に移動する場合はfalse。</param>
        public void MoveNextControl(bool forward = true)
        {
            if (forward)
            {
                SendKeys.Send("{TAB}");
            }
            else
            {
                SendKeys.Send("+{TAB}");
            }
        }
    }
}

MultilineプロパティがtrueのTextBoxは、Ctrl+Enterで改行される。
MoveNextControl()メソッドは、SelectNextControl()メソッドの『Tabキー押下版』。

このロジックを実装したフォームを継承してアプリを作ることで、面倒なことが起こらない。
EnterFocusプロパティなどを設けて、trueの時だけ処理するとか、継承元で考慮しておけば楽。