sou's blog

落ち着いた華やかさがあり、上品に明るく陽気なさまを表す。

Windowsアプリケーションで矢印キーとEnterでのフォーカス移動

というトンデモな仕様を実装しろとのこと。
明らかにWindows標準APIを無視した設計だったので、
仕様の再検討を!!ってまずお願いしたけど、一応調べてみた。

TextBoxなどでは、文字列にカーソル当たっている状態では左右キーは文字間を移動するのに使われる。
その為、キャレット位置が先頭のときに←を押すと前のコントロールへフォーカス
キャレット位置が最終のときに→を押すと次のコントロールへフォーカスという動きを考えた。
TextBoxには、SelectionStartというプロパティがあって簡単にキャレット位置を判定できたが、
こまったのはそれ以外のコントロールについて。
例えば、ComboBoxなんかも任意文字列が入力できるのでキャレット位置を取得したい。
TextBoxにあったSelectionStartプロパティが使えたらなーっと思ってたらこっちにもあった。

DRYじゃねぇ・・・。

とおもった。
TextBoxBaseクラスを継承してたり、Interfaceとかで提供されてて欲しかった。

一応コード
TextBoxのみ文字間移動を対応。その他については考慮していない
あと、実装したのは共通で利用するForm。(KeyPreviewプロパティをTrueにしておく)
共通で利用するFormを継承したFormで自動的に適用される。

        private void CommonForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Left)
            {
                if (this.ActiveControl is TextBox)
                {
                    TextBox textBox = (TextBox)this.ActiveControl;
                    if (textBox.SelectionStart != 0)
                    {
                        return;
                    }   
                }

                this.SelectNextControl(this.ActiveControl, false, true, true, true);
            }

            if (e.KeyCode == Keys.Right)
            {
                if (this.ActiveControl is TextBox)
                {
                    TextBox textBox = (TextBox)this.ActiveControl;
                    if (textBox.SelectionStart != textBox.Text.Length)
                    {
                        return;
                    }
                }

                this.SelectNextControl(this.ActiveControl, true, true, true, true);
            }

            if (e.KeyCode == Keys.Enter)
            {
                bool forward = e.Modifiers != Keys.Shift;
                this.SelectNextControl(this.ActiveControl, forward, true, true, true);
            }
        }