TextBoxのTextプロパティにコードから値をセットすると、次回フォーカス取得時になぜか全選択される

なんか謎の挙動を発見したのでメモ。

コード例

VBでもC#でもいいけど、適当にフォームを作って、テキストボックスとボタンを1個作成する。

で、ボタンのClickイベントに以下のコードを書く。以下の例はVB

TextBox1.Text = "hoge"

これを実行して、以下の手順をやってみる。

  1. ボタンをクリックする(テキストボックスに "hoge" と入る)
  2. TABキーでフォーカスをテキストボックスへ移動
  3. テキストボックスの文字が全選択されている!

これが問題の現象。なんで勝手に全選択されるの?という話。

普通にキーボードから文字を入力したときは、当然こんな現象は起きない。コードからTextプロパティに文字列をセットしたときだけ、そのあとテキストボックスにフォーカスが当たったとき(マウスのクリックによるフォーカス取得ではなく、TABキーやFocusメソッドによる場合だけ)に全選択されるようだ。

この挙動ってバグ?仕様?UI上そうなってる方が使いやすいとかの理由があってのことなの?そしてこれは.NETだけ?

回避策

いろいろわからないけど、とりあえず回避策は発見した。

TextBox1.Text = "hoge"
TextBox1.SelectionStart = TextBox1.SelectionStart

Textプロパティに文字をセットしたあと、SelectionStartプロパティを無意味に再代入する。かなり無駄なコードに見えるけど、これがちゃんと効いて、次回テキストボックスにフォーカスが来たとき、勝手に全選択されないようになる。

これで自然な感じになったかな。

回避策の使いどころ

もしもこの謎の挙動にちゃんとした意味があって、それを期待してアプリを使っている人がいるとしたら、安易にこの挙動を自分のアプリだけが回避してしまうのは良くないと思う。「どんなアプリも似たような使い勝手」というのは結構重要だから。

データをロードしてきてテキストボックスにセットするようなときはあえて回避せず、入力補完の意味合いでセットするときは回避する、みたいに、ちゃんと使いどころを考えるのが大事だと思う。

てか、値を代入するたびにSelectionStartを再代入するなんてコードを書きたくない。どうしても回避したい場合だけコメントで言い訳を書いた上でやるっていう程度でもいいかな。その言い訳の文章を書くときにこの記事のURLを載せておけば、説明が少し楽になるかも知れない。

まあ細かいことだけど

こういうの気になるよね。それにしてもいったい何なんだろう。