• 検索結果がありません。

バインドオブジェクトが、必然的に不整合状態に陥っている ことがありうる

ドキュメント内 Web フォームアプリケーション開発基礎 (ページ 31-42)

(BC/DAC)

注意点 2. バインドオブジェクトが、必然的に不整合状態に陥っている ことがありうる

例外ベースの検証=不正なデータをバインドオブジェクトが受け付けな いようになっている、ということ

しかし、そもそも入力フォームの表示直後のバインドオブジェクトは、何も 入力されていない=オブジェクトとして正しい状態ではない

あるいは、入荷予定日と出荷予定日を入力するような場合、フィールド間 の大小比較関係は、片方ずつデータ入力されてもうまくチェックできない

結果的に、インスタンス全体チェックは、イベントハンドラでの実装が必要

objCustomer オブジェクト

初期状態では何もデータが入っていない

=オブジェクトインスタンスとして正しい 状態ではない(例:非 null フィールド に対して null が入っていたりする)

不正なデータを入れられない

ようになっているが、そもそも

バインドオブジェクトの初期値

自体が不正なデータである

p.32

3. 単体入力エラーチェックの実装パターン

-② Silverlight 3, WPF 3 の場合

 つまり、ここまでの解説をまとめると、例外ベースの双方向 データバインドの動作イメージは以下の通りになる

 バインドエラーがない場合に限り、 UI からの入力がすべてバインドオ ブジェクトに反映されている

このためイベントハンドラ内では、まずバインドエラーのチェックが必要

 仮にバインドエラーがなかったとしても、インスタンス単位のチェックを イベントハンドラ内で行う必要がある

 このように、例外ベースの双方向データバインドは、実装が すっきりしないところがある

1973/06/07 Nobuyuki

1234

コードビハインド

( *.Forms.cs など)

バインドオブジェクト

同期できて いない場合が

ある

ビジネス ロジック部

( BC/DAC )

インスタンス 単位のエラーが

あることも

① バインドエラー有無のチェック

② インスタンス単位のチェック

③ 業務処理の呼び出し

3. 単体入力エラーチェックの実装パターン

-③ Windows フォーム 2.0, WPF 3.5 の場合

 こうした問題を解決するため、 Windows フォーム 2.0 や WPF 3.5 では、 IDataErrorInfo 入力検証がサポートされた

 IDataErrorInfo インタフェースは、オブジェクトインスタンス内部にエ ラーが含まれていることを、文字列情報として返すためのもの

 これを使うことにより、前述の問題をきれいに解決することができる

1973/55/41 Nobuyuki

12345

objCustomer オブジェクト

IDataErrorInfo

インタフェース

無理矢理 反映

内部に エラー値を

含む

顧客ID は半角英数大文字

4 文字でなければなりません。 エラー情報を

文字列として 外部に提供 UI コントロールが、

バインドオブジェクトの IDataErrorInfo から エラー情報を取り出して

UI に表示する

p.34

3. 単体入力エラーチェックの実装パターン

-③ Windows フォーム 2.0, WPF 3.5 の場合

 IDataErrorInfo オブジェクトを使った双方向データバインドは、

下図のように動作する

 入力値が正しかろうと間違 っていようと、とにかくオブ ジェクトに反映してしまう

 オブジェクトインスタンスが 不正な状態にある場合には これを IDataErrorInfo イン タフェースから公開する

 これにより、常に UI とオブ ジェクト内の値とが同期さ れる

 具体的な実装 → 次ページ

Customer Input オブジェクト

Customer Input オブジェクト

Customer Input オブジェクト

整合

正しくない 状態 エラー情報を

返す

public class CustomerInput : IDataErrorInfo {

private Dictionary<string, string> _errors = new Dictionary<string, string>();

private string _id;

public string ID {

get { return _id; } set

{

_id = value;

if (_id == null) {

_errors["ID"] = "ID は必須入力項目です。";

}

else if (Regex.IsMatch(value, @"^[0-9A-Z]{4}$") == false) {

_errors["ID"] = "ID は半角英数大文字 4 文字です。";

} else {

_errors["ID"] = null;

} } }

private string _name;

public string Name {

get { return _name; } set

{

_name = value;

if (_name == null || _name == "") {

_errors["Name"] = "名前は必須入力項目です。";

}

C#

単体入力エラーがある 値であっても、とりあえ ず受け付けてデータの 同期を図る

当該入力値が不適切 な場合には、エラー情 報をため込んでおく

IDataErrorInfo ベースの双方向 バインドオブジェクト

p.36

else {

_errors["Name"] = null;

} } }

private string _email;

public string Email {

get { return _email; } set

{

_email = value;

if (value == null || Regex.IsMatch(value, @"¥w+([-+.']¥w+)*@¥w+([-.]¥w+)*¥.¥w+([-.]¥w+)*")) {

_errors["Email"] = null;

} else {

_errors["Email"] = "電子メールアドレスとして有効な値を入力してください。";

} } }

private string _phone;

public string Phone {

get { return _phone; } set

{

_phone = value;

if (value == null || Regex.IsMatch(value, @"(0¥d{1,4}-|¥(0¥d{1,4}¥) ?)?¥d{1,4}-¥d{4}")) {

_errors["Phone"] = null;

} else

C#

IDataErrorInfo ベースの双方向 バインドオブジェクト

{

_errors["Phone"] = "電話番号は (03)1234-5678 のように入力してください。";

} } }

public DateTime? Birthday { get; set; } // 全体整合チェック

public string Error {

get {

if (_email == null && _phone == null) {

return "電子メールアドレスか電話番号かのいずれか一方は必須入力です。";

} else {

return null;

} } }

public bool HasErrors {

get { return (_errors.Count != 0 || Error != null); } }

public string this[string columnName]

{ get {

return (_errors.ContainsKey(columnName) ? _errors[columnName] : null);

} } }

C#

特定カラム(プロパティ)にエラーがある場 合には、そのエラーの情報をメッセージで返 す

※ここから入手されるエラー情報は、

ErrorProvider とBindingSource により自 動的にアイコンで表示される

※このメソッドは必須ではないが、実装して おくとUI 実装がラクになる

オブジェクト全体に対するデータ検証内容は、こ こに記述する

(エラーがない場合にはnull を返す)

IDataErrorInfo インタフェース経由で エラー情報を返すための処理

IDataErrorInfo ベースの双方向 バインドオブジェクト

p.38

3. 単体入力エラーチェックの実装パターン

-③ Windows フォーム 2.0, WPF 3.5 の場合

 具体例) Windows フォーム 2.0 の場合の IDataErrorInfo 双方向データバインドの実装方法

 前述のように作成した IDataErrorInfo オブジェクトを BindingSource コントロールにより UI コントロール群と接続する

 さらに画面上に ErrorProvider コントロールを貼り付けておくと、これ が自動的にエラー情報をチェックし、アイコンなどの表示をしてくれる

電子メールアドレスとして有効なアドレスを入 力してください。

3. 単体入力エラーチェックの実装パターン

-③ Windows フォーム 2.0, WPF 3.5 の場合

 IDataErrorInfo ベースの双方向データバインドには、以下の ようなメリットがある

 単体入力チェック処理を、バインドオブジェクトに固めることができる

このため、モジュールの役割分担が明確になる( MVC 的なモデル)

しかも、単体入力チェックロジック部分だけを重点的に単体機能テストす ることもできる

1973/55/41 Nobuyuki

12345

コードビハインド

( *.Forms.cs など)

バインドオブジェクト

ビジネス ロジック部

( BC/DAC )

IDataErrorInfo インタフェース UI 表示

エラー表示

単体入力 チェックロジック

UI / BC との

接続処理 業務処理

常に同期 エラー

表示

p.40

3. 単体入力エラーチェックの実装パターン

-③ Windows フォーム 2.0, WPF 3.5 の場合

 入力仕掛り状態の維持が簡単にできる

バインドオブジェクトをそのままシリアル化して保存すれば、入力しかけ のデータをそのまま保存しておくこともできる

 コードビハインドの記述が簡単になる

コードビハインドのイベントハンドラでは、バインドオブジェクトだけを操作 すればよく、 UI コントロールを触る必要がない

このため、コードビハインドのコードの見通しも非常によくなる

→ 次ページ参照

1973/55/41 Nobuyuki

12345

コードビハインド

( *.Forms.cs など)

バインドオブジェクト

ビジネス ロジック部

( BC/DAC )

IDataErrorInfo インタフェース

常に同期

C#

public partial class Form1 : Form // ※ 一部コードを省略 {

private CustomerInput ci;

private void Form1_Load(object sender, EventArgs e) {

ci = new CustomerInput();

bindingSource1.DataSource = ci;

}

private void bindingSource1_BindingComplete(object sender, BindingCompleteEventArgs e) {

lblError.Text = ci.Error;

}

private void button1_Click(object sender, EventArgs e) {

// 単体入力チェックの結果を確認 if (ci.HasErrors)

{

MessageBox.Show("入力データに誤りがあります。修正してください。");

return;

}

// 単体入力チェックが OK なら、ビジネスロジックを呼び出す

localhost.CustomerService proxy = new localhost.CustomerService();

var result = proxy.ResistCustomer(ci.ID, ci.Name, ci.Phone, ci.Email, ci.Birthday);

// 正常終了と業務エラー(突き合わせエラー)を切り分けてメッセージ表示 switch (result)

{

case localhost.RegistCustomerResult.Success:

MessageBox.Show("正しく顧客登録を行いました。");

break;

case localhost.RegistCustomerResult.DuplicateCustomerIDError:

MessageBox.Show("指定された ID はすでに利用されています。");

break;

} } }

単体入力チェックを 実施する

戻り値を switch 文などにより 分岐させて後処理を行う

UI

p.42

3. 単体入力エラーチェックの実装パターン

- 3 つの実装方式の比較

 これらの 3 つの実装方式は、単体入力チェックに対する考え

ドキュメント内 Web フォームアプリケーション開発基礎 (ページ 31-42)

関連したドキュメント