Windows Formの検証機能
Windows Formの検証機能は2.0で大幅に強化されそれなりに実用的になっている。
しかし、案外癖があって???状態になることも多い。
以前部分的に書いたことがあったのだが、利用上のポイントを簡単にまとめてみたい。
Validatingイベント
最初にWindows Formで検証を行うために用意された最も基本的な仕組みは各コントロールのValidatingイベントである。
Validatingイベントの処理では入力された値のチェックを行い、もしエラーがあればエラーメッセージを表示したりする処理を記述する。CancelEventArgsのCancelプロパティをtrueにするとそのコントロールにフォーカスを残すことができる。
private void textBox1_Validating(object sender, CancelEventArgs e) { int work; if (!int.TryParse(textBox1.Text, out work)) e.Cancel = true; }
CausesValidationプロパティ
次に、重要なポイントが各コントロールのCausesValidationプロパティである。分かってしまえばたいしたことは無いのだが、どの様にフォームの検証メカニズムに影響を与えるか知っておく必要がある。
- パターン2 CausesValidationがtrueからfalseへのコントロールの移動
- この場合には移動先が検証メカニズムに参加していないため、移動元のコントロールのValidatingイベントは発生しない。
- パターン3 CausesValidationがfalseからfalseへのコントロールの移動
- このパターンはパターン2と同じになる。
- パターン4 CausesValidationがfalseからtrueへのコントロールの移動
- このパターンは少し複雑で、移動元のコントロールは検証メカニズムに参加していないためValidatingイベントは発生していないのだが、それよりも前の移動元でCausesValidationがtrueのコントロールがあるとそのコントロールのValidatingイベントが発生するという動きをする。
これらから、CausesValidationを単に移動元のコントロールのValidatingイベント発生を制御するフラグというよりも、フォームの検証メカニズムに参加するかどうかを表しているということになる。
あと、PanelなどのコンテナのCausesValidationも影響するので注意が必要。要はPanelのCausesValidationがtrueになっているとその中のButtonのCausesValidationがfalseでもValidatingイベントが発生するということ。
Validate・ValidateChildrenメソッド
ここからが2.0の新機能であるが、
まずは、FormのValidateメソッドとValidateChildrenメソッドである。
これらはいずれも、プログラムから明示的にValidatingイベントを発生させる仕組みである。ValidateChildrenを利用するとまとめてValidatingイベントを発生させることもできようになっている。
良く出てくるケースとして、BindingNavigationの保存ボタンを押してもValidatingイベントが発生しないのだが、これはToolStripButtonのCausesValidationがfalseになっているためで、Validateメソッドで明示的に移動元のValidatingイベントを発生させることで対処することができる
AutoValidateメソッド
次にValidatingの動作自体を制御するためのFormのAutoValidateプロパティであるが、これを利用するとValidatingイベントの発生の有無を制御することができる。指定可能なオプションは、Disable・EnableAllowFocusChange・EnablePreventFocusChange・Inheritの4つである。Diableを指定するとフォームが発生させる暗黙的なValidatingを抑制することができる。たとえば、フォームのClose処理を実行すると暗黙的なValidatingが発生してしまい困ることがあるが、以下のように記述することで回避することができる。
//button1.CausesValidation = falseに設定されている必要がある private void button1_Click(object sender, EventArgs e) { this.AutoValidate = AutoValidate.Disable; this.Close(); }
関連して、コントロールボタンのxを選択した場合にValidatingイベントが発生して画面がクローズされない問題についてはFormClosingをハンドリングして対処する。
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { e.Cancel = false; }
ただ、この場合コントロールのValidatingイベント自体は発生してしまうのでこれを対処する場合、WndProcをオーバーライドするようなことで対処が必要になってくる。
//たぶん動作すると思うけど未確認コード private const int WM_CLOSE = 0x10; protected override void WndProc(ref Message m) { if (m.Msg == WM_CLOSE) { AutoValidate = AutoValidate.Disable; } base.WndProc(ref m); }
Binding.DataSourceUpdateModeプロパティ
最後にデータバインドとのからみでBinding.DataSourceUpdateMode について、DataSourceUpdateModeはOnValidation・OnPropertyChanged・Neverの3つのモードがあるが、ここではOnValidationの場合の動作、Validatingイベントでプロパティが正常に検証されるとデータソースが更新される点だけ取り合えず記憶しておく。逆に言うとValidatingイベントが発生しないとデータソースに入力値が反映されない点に注意しておけばよいということになる。
ちなみに、ComboBoxなどで選択した値によって他の入力コントロールの状態を変えたいような場合、ComboBoxのSelectedItemをOnPropertyChangedにして即座に反映させる方法もあるが、SelectedIndexChangedでWriteValueを実行する方法もある。