BindingSourceと単純なコントロールをバインドする
BindingSourceとしてTextBoxをはじめとするUI系コントロールとバインドした時に、入力値が誤っている場合にフォーカスが外れなくなる障害が発生した。その調査を行っていて気付いたこと、分かった事について以下にまとめる。*1
バインドした時に期待されるのがBindingSourceとControlの同期である。ここでの同期とは以下の事を指す。
- Adapterを介して取得したデータ情報がBindingSourceに格納されることでバインドを設定した項目情報がControlに描画を含めて反映される
- ユーザがControlに入力した情報がプログラムを記述することなく、BindingSourceに反映される。
同期の仕組は「変更通知」により実現している。BindingSourceとControlがそれぞれ変更を通知しあって値を設定・描画等を行っている。
ControlからBindingSourceへの変更通知のとき、Controlの情報を「検査」する。
「検査」結果がOKであればBindingSourceに格納します。NGの場合は処理をキャンセルする。
以下にフローチャートを記述する。
検査はバインドしているDBの項目に一致しているかどうかを検査する。
例えば、日付型の項目とバインドしている(Control)テキストボックスに0000/00/00を入力する。すると、結果がfalse(DBに設定することが出来ない値)と判断され、処理がキャンセルされる。
この処理を行っている時に発生するイベントをValidatingとValidatedという。
ValidatingとValidated
このイベントはLeave→Validating →Validatedの順番で発生する。コントロールがフォーカスを失って(Leave)、ユーザの入力を検査し(Validating)、検査後にBindingSourceに値を反映する(Validated)。もし検査が誤った場合、Validatingは「フォーカスを失う」処理をキャンセルし、Validatedは発生しない。
対応策案
ValidatingとValidatedのため、バインドしたコントロールはDB登録が不可能な値を設定した時にフォーカスが外れない、という障害が発生した。この症状に対応するには以下の方法が考えられる。
- Control.CausesValidation プロパティをFalseにする
CausesValidationは前述したValidatingとValidatedを抑止するプロパティである。これをFalseにすると検査と検査後の設定処理が行われなくなるため、「誤った値が設定されたとき」にフォーカスが外れなくなることはなくなる。
- 問題点
ValidatingとValidatedはControlの値を検査し、BindingSoruceに設定する動作を行っていたため、これを抑止するとControlとBindingSoruceの同期がとれなくなってしまう。
対応策として、バインドしているControlの値を直接BindingSoruceに設定する事が考えられるが、バインドの利点が無くなってしまう。
- Leaveイベント時に値を設定する。
Leaveイベント時にDB項目として矛盾しない値を設定すると、この問題は発生しなくなる。
- 問題点
自動的に値が設定されてしまうので、入力ユーザが意図しない値が登録されてしまう可能性がある。
そのため、以下の制御が考えられる。
- ユーザが分かりやすいように背景色を設定する(登録する・しないはユーザまかせ)
- 異常フラグ等を設定して、登録前に全項目をチェックし、その状態の時は登録を行わないようにする(システムで制御)
参考:
http://msdn.microsoft.com/ja-jp/library/xz45s2bh%28v=vs.85%29.aspx
http://msdn.microsoft.com/ja-jp/library/ms993236.aspx
*1:前に調べたものをdocにまとめてたんですけど、間違いとかありそうなので、こちらにアウトプット。
図で〜とか言ってるところは、wordで書いてたので省略。後から追記するかもしれません。