Windows Forms 入力検証 - エラー項目のフォーカスをロックするパターン

これまでの経験上、画面の単項目入力検証のコードは汚くなりがちなところの1つだ。Windows Forms が提供している機能に対する知識不足のせいで、どうしても無理やり仕様を満たすためのトリッキーなコードを書いてしまうことが多い。そんなことをしているので、後々の障害対応や仕様変更のときにイヤな思いをするはめに...

そこで、Windows Forms の入力検証について、要件毎に実装パターンをまとめようと思う。まずは、入力エラーがあるコントロールからフォーカスをはずせないように実装するパターン。

要件

こんな画面を考える。

この画面を作る上で、このような要求があるとする。できるだけコードが汚くならないように、この画面を実装したい。

  • TextBox に必須入力チェックを実装し、エラーがあった場合は TextBox からフォーカスがはずれないようにする。
  • Register ボタンをクリックした際、画面の全項目の入力チェックを実施し、エラーがあった場合は処理を中止する。
  • TextBox に入力エラーがある状態でも、Cancel ボタンと閉じるボタン (タイトルバー右の) はクリックできる。

実装

以下のようにプロパティとイベントの設定を行う。

TextBox の設定

TextBox の入力検証を行う処理を実装する。入力エラーがある場合、e.Cancel に true を設定することで、フォーカスがはずれなくなる。

private void ValidateTextBoxIsNotEmpty(object sender, CancelEventArgs e)
{
TextBox textBox = (TextBox)sender;
if (String.IsNullOrEmpty(textBox.Text))
{
this.errorProvider1.SetError(textBox, "This text box must have value.");
e.Cancel = true;
}
else
{
this.errorProvider1.SetError(textBox, String.Empty);
}
}



Register ボタンの設定

処理を実行する直前に、画面の全コントロールの入力チェックを行う場合は、ValidateChildren() を呼び出す。Form 内の各コントロールの Validating イベントハンドラが実行され、その内一つでも e.Cancel = true を設定するものがあれば、ValidateChildren() から false が返される。



private void Register(object sender, EventArgs e)
{
if (ValidateChildren())
{
MessageBox.Show("Registration succeeded.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Registration failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}



Cancel ボタンの設定

TextBox の Validating イベントハンドラで、e.Cancel = true にしているので、入力エラーがある場合は TextBox からフォーカスがはずれなくなっている。フォーカスがはずれないので、ボタンクリックもできないが、Cancel ボタンだけはクリックしたい。その時は CausesValidation を false に設定する。CausesValidation = false にすると、「Cancel ボタンにフォーカスを移す直前のコントロールで入力検証をしない」という動作になるので、入力エラーがある TextBox からも Cancel ボタンにフォーカスを移動できる。



イベントハンドラの方には、特に必要な処理はない。



private void Cancel(object sender, EventArgs e)
{
MessageBox.Show("Cancellation succeeded.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}



Form の設定

TextBox の Validating イベントハンドラで、e.Cancel = true にしていると、入力エラー時はタイトルバーの閉じるボタンも押せなくなる。これを回避するためには、OnFormClosing() をオーバーライドして、e.Cancel = false としておく。



protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
e.Cancel = false;
}

Comments

Popular posts from this blog

TFS: 別PCでのチェックアウトを取り消す

WPF の RichTextBox に文字列を設定する&取り出す

WPFアプリにアニメーションGIFを表示させる