2009-08-28 11 views
1

フォームにビジネスオブジェクトの境界が設定されています(各プロパティはコントロールにバインドされています)。いくつかのビジネス仕様があります(このフィールドは空であってはいけません。このフィールドは0以上でなければなりません)。すべてのルールをチェックする最良の方法は何ですか?C#フォームにバインドされたオブジェクトを「検証する」最良の方法

現在、私は各コ​​ンロールのバリデータを持っていますので、すべてのバリデータがOKであることを確認できますが、この解決策は本当に気に入らないです。実際にルールは破棄されており、すぐにすべてを見ることは容易ではありません。

すべてのルールをチェックする大きなメソッドCheckValidatyを持つことができますが、これはバリデーターとの二重チェックにつながります。

あなたは何をしますか、他の解決策はありますか?

+0

WPFまたはWinformsの? –

答えて

5

私は、BusinessObjectにIDataErrorInfoを実装させることをお勧めします。私はそれがビジネスエラーを処理する最もクリーンな方法だと思います。

これらのリンクを見てみましょう:

  1. http://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo_members.aspx
  2. http://www.codegod.de/WebAppCodeGod/objectdatasource-and-idataerrorinfo-with-winforms-AID427.aspx
+0

ニース!あなたの答えは私のものよりも好きです。 UI固有のエラーがある場合は、混在して一致するように見えます。 – XXXXX

0

バリデーターアプローチで何が問題になっていますか?それはまったく受け入れられ、独自のルールを実装するために自分で書くことができます。

+0

Infactカスタムコントロールとバリデーターがコントロール内にあるので、バリデーターをvalidatorプロパティとして宣言します(例:valueCanBeNull = true)。しかし、このアプローチは、ルールに下線を引いていません。同僚が特定のルール、すべてのルールを見つけることは容易ではありません。 – Toto

3

検証には、データ固有の検証(永続性レイヤー内)とユーザーインターフェイス検証の2種類があります。私は入力側の近くにバリデーションを置くことをお勧めします。なぜなら、一般的にユーザーに何が間違っているのかを見せたいからです。また、ユーザーインターフェイスにデータ検証を接続しようとすると、データバインディング間接参照に一致する間接参照が追加されます。

コントロールクラスにデータ検証を行うのは良い考えのようではありません。基本的に、コントロールクラスは特定の1つのフィールドに対してのみ使用できます。

標準のWindowsフォームのやり方は、コンテナにデータ検証を入れることです。このようにして、検証では他のプロパティの状態をチェックし、特定のコントロールをErrorProviderオブジェクトに接続して適切なエラーメッセージを表示することができます。

class EmployeeForm : UserControl 
{ 
    EmployeeObject employee; 

    // ... 

    void employeeNameTextBox_Validating (object sender, CancelEventArgs e) 
    { 
     if (employee.Name.Trim().Length == 0) { 
      errorProvider.SetError (employeeNameTextBox, "Employee must have a name"); 
      e.Cancel = true; 
     } 
    } 

    void employeeHireDateControl_Validating (...) 
    { 
     if (employee.HireDate < employee.BirthDate) { 
      errorProvider.SetError (employeeHireDateControl, 
       "Employee hire date must be after birth date"); 
      e.Cancel = true; 
     } 
    } 
} 

class ExplorerStyleInterface : ... 
{ 
    // ... 

    bool TryDisplayNewForm (Form oldForm, Form newForm) 
    { 
     if (! oldForm.ValidateChildren()) 
      return false; 

     else { 
      HideForm (oldForm); 
      ShowForm (newForm); 
      return true; 
     } 
    } 
}

標準WFの方法は、コントロールがValidateChildrenがコンテナ(またはコンテナのコンテナ)に呼び出されたときに焦点を合わせるか、失ったときに、特定の制御のための検証イベントを発生することです。このイベントのハンドラは、コンテナのコントロールのイベントプロパティを使用して設定します。ハンドラは自動的にコンテナに追加されます。

エラーの重視を拒否するデフォルトの動作(コンテナのAutoValidateプロパティを設定することによって変更できます)を気に入らないかぎり、この方法がなぜ機能しないのかわかりませんコンテナのコンテナ)をEnableAllowFocusChangeに設定します。

Windowsの標準的なフォームのやり方について気に入らないものを具体的に教えてください。代替案を提供したり、標準的なやり方であなたが望むことを実行できるかどうかを説得することができます。

+0

私はこのアプローチが好きです。これについて深く考えよう。他の人が食べ物を食べたいと思ったら、時間のチャンクには答えないでください。 – Toto

1

あなたはこのような状況がある場合:

- Many controls in the Winform to 
    validate 
    - A validation rule for each control 
    - You want an overall validation within the Save() command 
    - You don't want validation when controls focus changes 
    - You also need an red icon showing errors in each control 

を次に次のコードをコピーして貼り付けることができます2つのテキストボックスと保存ボタンを持つフォームを実装しています:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace ValidationApp 
{ 
    public class ValidationTestForm : Form 
    { 
     private TextBox textBox1; 
     private TextBox textBox2; 
     private Button btnSave; 
     private ErrorProvider errorProvider1; 

      /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.components = new System.ComponentModel.Container(); 
      this.textBox1 = new System.Windows.Forms.TextBox(); 
      this.textBox2 = new System.Windows.Forms.TextBox(); 
      this.btnSave = new System.Windows.Forms.Button(); 
      this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components); 
      ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit(); 
      this.SuspendLayout(); 
      // 
      // textBox1 
      // 
      this.textBox1.Location = new System.Drawing.Point(131, 28); 
      this.textBox1.Name = "textBox1"; 
      this.textBox1.Size = new System.Drawing.Size(100, 20); 
      this.textBox1.TabIndex = 0; 
      // 
      // textBox2 
      // 
      this.textBox2.Location = new System.Drawing.Point(131, 65); 
      this.textBox2.Name = "textBox2"; 
      this.textBox2.Size = new System.Drawing.Size(100, 20); 
      this.textBox2.TabIndex = 1; 
      // 
      // btnSave 
      // 
      this.btnSave.Location = new System.Drawing.Point(76, 102); 
      this.btnSave.Name = "btnSave"; 
      this.btnSave.Size = new System.Drawing.Size(95, 30); 
      this.btnSave.TabIndex = 2; 
      this.btnSave.Text = "Save"; 
      this.btnSave.UseVisualStyleBackColor = true; 
      this.btnSave.Click += new System.EventHandler(this.btnSave_Click); 
      // 
      // errorProvider1 
      // 
      this.errorProvider1.ContainerControl = this; 
      // 
      // ValidationTestForm 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(266, 144); 
      this.Controls.Add(this.btnSave); 
      this.Controls.Add(this.textBox2); 
      this.Controls.Add(this.textBox1); 
      this.Name = "ValidationTestForm"; 
      this.Text = "ValidationTestForm"; 
      ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit(); 
      this.ResumeLayout(false); 
      this.PerformLayout(); 

     } 

     #endregion 

     public ValidationTestForm() 
     { 
      InitializeComponent(); 

      // path validation 
      this.AutoValidate = AutoValidate.Disable; // validation to happen only when you call ValidateChildren, not when change focus 
      this.textBox1.CausesValidation = true; 
      this.textBox2.CausesValidation = true; 
      textBox1.Validating += new System.ComponentModel.CancelEventHandler(textBox1_Validating); 
      textBox2.Validating += new System.ComponentModel.CancelEventHandler(textBox2_Validating); 

     } 

     private void textBox1_Validating(object sender, System.ComponentModel.CancelEventArgs e) 
     { 
      if (textBox1.Text.Length == 0) 
      { 
       e.Cancel = true; 
       errorProvider1.SetError(this.textBox1, "A value is required."); 
      } 
      else 
      { 
       e.Cancel = false; 
       this.errorProvider1.SetError(this.textBox1, ""); 
      } 
     } 

     private void textBox2_Validating(object sender, System.ComponentModel.CancelEventArgs e) 
     { 
      if (textBox2.Text.Length == 0) 
      { 
       e.Cancel = true; 
       errorProvider1.SetError(this.textBox2, "A value is required."); 
      } 
      else 
      { 
       e.Cancel = false; 
       this.errorProvider1.SetError(this.textBox2, ""); 
      } 
     } 



     private void btnSave_Click(object sender, EventArgs e) 
     { 
      if (this.ValidateChildren()) //will examine all the children of the current control, causing the Validating event to occur on a control 
      { 
       // Validated! - Do something then 
      } 

     } 
    } 
} 

注:

textBox1_Validating, textBox2_Validating...do the rule check 
関連する問題