6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C#・.NET Framework・WinForms】テキストボックスの内容が不適切であった場合に再度フォーカスする方法

Last updated at Posted at 2023-06-23

以下のようなテキストボックス (Name: SampleTextBox) があるとして、このテキストボックスには数字しか入力できないようにするとします。
image.png
image.png

仮に数字以外が入力された場合、このテキストボックスに再度フォーカスが当たって入力可能になるようにするにはどうすれば良いか? というのが今回の内容です。

以下の動画のような動きを目指します。
完成イメージ

その1:Focus メソッドを使う

フォーカスを当てることのできる (選択可能な) コントロールには Focus メソッドが組み込まれています。

SampleTextBox に入力された内容が適切かどうかを条件式で判定して、もし不適切であれば Focus メソッドで再度フォーカスを当てる、という方法です。

C#
using System.Text.RegularExpressions;

if (!Regex.IsMatch(SampleTextBox.Text, @"^[0-9]*$"))  // 入力された内容がすべて数字かどうか判定
{
    MessageBox.Show("数字以外が入力されています");
    SampleTextBox.Focus()
}

簡単な方法なので初心者のうちはついつい多用してしまいがちですが、フォームのロード時には Focus メソッドは使えないので注意が必要です。

また、公式ドキュメントには Focus メソッドが使えないコントロールが挙げられています。

次の一覧のWindows フォーム コントロールは選択できません。 これらのコントロールから派生したコントロールも選択できません。

Panel

GroupBox

PictureBox

ProgressBar

Splitter

Label

LinkLabel (コントロールにリンクがない場合)

その2:テキストボックスをアクティブにする

「テキストボックスにフォーカスを当てる」ということは、厳密にはテキストボックスをアクティブにすることに他なりません。なので、入力内容が不適切であると判定した際に、テキストボックスをアクティブにしてやると良さそうです。

コントロールに組み込まれている Select メソッドをつかって、テキストボックスをアクティブにすることができます。

C#
using System.Text.RegularExpressions;

if (!Regex.IsMatch(SampleTextBox.Text, @"^[0-9]*$"))  // 入力された内容がすべて数字かどうか判定
{
    MessageBox.Show("数字以外が入力されています");
    SampleTextBox.Select()
}

Focus メソッドとほぼ変わりません。
Select メソッドで使えないコントロールも公式ドキュメントに記載されていますが、こちらも Focus メソッドと同じでした。

Select メソッドと Focus メソッドの違い

戻り値

公式ドキュメントによると、Select メソッドの定義は以下の通りです。

コントロールをアクティブにします。

C#
public void Select ();

Focus メソッドの定義は以下の通りです。

コントロールをアクティブにします。

C#
public bool Focus ();

Focus メソッドには bool 型の戻り値が設定されています。Select メソッドはコントロールに正常にフォーカスを当てることができても特に何か返すわけではないが、Focus の場合はフォーカスを当てることができたら true、できなければ false を返してくれるみたいです。

フォームのロード時に使えるかどうか

一方、Select メソッドはフォームのロード時に使うことができます。

C#
public class SampleForm: Form 
{
  public void SampleForm_Load(object sender, EventArgs e)
  {
    SampleTextBox.Focus();  // 機能しない
    SampleTextBox.Select();  // フォーカスが当たる
    this.ActiveControl = SampleTextBox;  // フォーカスが当たる
  }
}

本題とは少しずれますが、フォームが開いた際に最初からフォーカスが当たっている状態にしたい、といったときに便利です。

また、親であるフォームの ActiveControl プロパティにテキストボックスをセットすることでも、テキストボックスをアクティブにすることができます (ActiveControl プロパティと Select メソッドはほぼ同じ動きをします)。

その3:テキストボックスの Validating イベントを使う

テキストボックスには Validating イベントを追加できます。これはテキストボックスなどのコントロールから別のコントロールに移る際に呼び出されるイベントで、呼び出された際にイベントとしてセットされたメソッドの処理が実行されます。
image.png
上記の Validating という項目をダブルクリックすると、対応するメソッドが自動で生成されます。とても便利。

再度テキストボックスにフォーカスを与える処理は以下のようになります。

C#
SampleTextBox_Validating(object sender, CancelEventArgs e)
{
  Textox tb = (TextBox)sender;
  if (!Regex.IsMatch(tb.Text, @"^[0-9]*$"))  // 入力された内容がすべて数字かどうか判定
  {
    e.Cancel = true;
  }
}

Validating イベントではメソッドに CancelEventArgs 型の値が渡されます。この値の Cancel プロパティを true にしてあげると、別コントロールへのフォーカス遷移をキャンセルしてくれます。

つまり、テキストボックスに数字以外の文字が入力されていた場合、送信ボタンを押したとしても内容が送信されず、送信ボタンを押す前の状態 (テキストボックスの入力待ち状態) に戻る、というわけです。ジョジョのGERみたい。

ただし、こいつにも弱点があります。それは、「遷移先の CausesValidation プロパティが false なら、遷移元の Validating イベントは無視される」という点です。
テキストボックスが入力待ちであっても他のボタンを押したい、というときに CausesValidation プロパティは役に立つのですが、送信ボタンなど「テキストボックスの中身が正しくないと選択しちゃダメ」みたいなコントロールの CausesValidation プロパティは極力いじらないのが良さそうです。

参考

CausesValidation プロパティを使った一例を取り扱っています。

6
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?