SpecExpressImplementation
First of all this implementation is not using the EntityFramework that we will probably go to in future releases. Rather it is an elegant addition to our current hack (e.g. the ongoing effort to organize the growing mire into something other than the big ball of mud).
Procedure for implementation on each Data Object
Step 1: Write the Specification
A specification looks like this:
public class PartIdentificationDataSpecification : Validates<PartIdentificationData> { public PartIdentificationDataSpecification() { IsDefaultForType(); Check(c => c.locusIdentity).Required(); Check(c => c.locusNumber).Required().GreaterThan(0); Check(c => c.site).Required(); Check(c => c.season).Required(); Check(c => c.field).Required(); Check(c => c.square).Required(); Check(c => c.DateStart).Required(); Check(c => c.DateEnd).Optional(); Check(c => c.supervisor).Required(); Check(c => c.balk).Optional(); Check(c => c.designation).Optional(); } }
Step 4: Modify the Controls for each object
For each object there are "Controls" that were POCO that must be changed into inheriting from UserControl. This is necessary to validate properly (don't ask its a long story).
Inherit form UserControl (01)
Add a private System.ComponentModel.IContainer components (02)
Create a constructor that calls InitializeComponent() - this is a change from what we have done. We always did want to make these identical in that sense. So do it now! (03)
Now, change the name of Initialize... to InitializeComponent and make the changes shown in (04)
Now you have a real component that can be used as such in the future.
... (01) public class IdentificationControls : UserControl ... (02) private System.ComponentModel.IContainer components; ... (03) public IdentificationControls() { InitializeComponent(); } ... (04) public void InitializeComponent() { components = new Container(); ... //Add the controls to the user control Controls.AddRange(new System.Windows.Forms.Control[] { this.panelIdentification }); } === Step 3: Implement Verification in the BusinessObject (those under Data) === 1. Add the IDataErrorInfo interface to the Class (01) 1. Add a new property: string Error (02) 1. Add two private variables: BindingSource myBindingSource (03) and ErrorProvider myErrorProvider (04) 1. Add instantiation of the two new private variables and set their values as shown in in (05) - (09). This effectively binds the graphic elements of the component to this object and allows the IDataErrorInfo to worry about the validation. 1. Add the required interface method in the Interface Methods region (10) - (11). This is what actually calls the Spec Express Framework. {{{ 01 public class PartIdentificationData : IDataErrorInfo ... 02 //for validation purposes public string Error { get { return _lastError; } } ... 03 private BindingSource myBindingSource; 04 private ErrorProvider myErrorProvider; ... private void buildControl() { //The next two lines create a BindingSource for validation purposes 05 myBindingSource = new BindingSource(); 06 myBindingSource.DataSource = this; //Get the "View" IdentificationControls idcs = new IdentificationControls(); idcs.InitializeIdentificationControls(); idCtrl = idcs.panelIdentification; //Create an Error Provider to show errors to the user. 07 myErrorProvider = new ErrorProvider(); 08 myErrorProvider.DataSource = myBindingSource; 09 myErrorProvider.ContainerControl = idcs; ... 10 #region Interface Methods public string this[string fieldName] { get { try { switch (fieldName) { case "Error": return _lastError; default: _lastError = ValidationExpressions.getErrorMessage(this, fieldName); break; } } catch (Exception ae) { System.Windows.Forms.MessageBox.Show("PartIdentificationData through an exception while trying to validate Filed\"" + fieldName + "\"\n\n" + ae.Message); } return _lastError; } } 11 #endregion