How to link a class of validation methods to VCL field components?

ttheimer used Ask the Experts™
I am refactoring a financial product.  I have a set of 6 fields that appear many times through the program (amount, start date, cost-of-living adjustment, etc).  sometimes these are individual edit components and sometimes they are columns in a grid.  As per usual all sets require the same basic set of validations and error responses.

I currently use functions to perform the validations.  I see some advantages to moving these functions into a class so that each field set is represented by an instance of the class.   But my question is how to best "link" or relate each of the fields - VCL edit components - to the class instance so that an onchange event in the editor would launch the appropriate validation method.

I get a bit fuzzy with class design when the properties are object references which is what would seem to be required here.  As stated above I am looking for a recommended means for linking field components to the class instance so that component events can trigger validation methods.  Please let me know if more details are needed regarding the nature of the problem.

Currently in Delphi 2007 but can upgrade if new features offer a better solution.


Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Geert GOracle dba
Top Expert 2009

you need to consider a few approaches

1: a common event handler
in this event handler you can look what component it is and call a validation class

2: create your own descendant of a TEdit (or TDBCombobox, or ...)
you need to look how many types of editors you have

with both approaches you can use a validation class
you could use a strategy pattern
Oracle dba
Top Expert 2009
if you want a other sample of a strategy pattern, you can find one here



I'll be reading the Gustavson article on Patterns today.

Regarding the idea for a common event handler - that is what I am using now with my component sets defined at design time as an array of records.  The challenge is identifying which set the sender component belongs to: e.g., when Amount is changed and the onchange event is fired, the validation handler must identify which Start Date component is associated with the changed Amount to verify that Start Date is not empty.

An event handler only receives the Sender parameter so currently I am looping through all of the sets to find a match to the Sender object.  Then I know which set the Sender belongs to and I know which associated fields to use in the validation process.  It just seems excessive for each event handler to need to include the looping search routine.  I thought that using a class to define the "sets" might provide an easier means of identifying associated components.
Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

Could you post a sample of your code here, please?



Didn't know what you wanted to see in a code sample.  The code here shows the declaration of the record and the array of records, the initial loading of one of these records, and an example event handler that must find the record belonging to the Sender so that validation can proceed with data from associated fields.

Let me know if you were looking for something else / additional.


uses . . .;

  TCOLASet = record
    AmountCurObj: TObject;
    AmountDescrStr: String;
    YrEdtObj: TObject;
    BegDtpObj: TObject;
    EndDtpObj: TObject;
    COLAEdtObj: TObject;
    DataSrc: TDataSource;
. . .
    /// Declaring the array of records.  The size of the array can 
    /// no longer be static, need to be able to add records
    /// (component sets) at run time.
    COLAObjAR: Array[1..8] of TCOLASet;
. . .

procedure TfrmMain.FormCreate(Sender: TObject);
  . . .     //////////////////////////////////////////////////////////////////
      ///  example loading of one of the records with a component set.
  COLAObjAR[1].AmountCurObj := cedIR_TtlToFund;
  COLAObjAR[1].AmountDescrStr := '''Total Monthly Needed to Fund''';
  COLAObjAR[1].YrEdtObj := edtIR_TtlToFundPCYrs;
  COLAObjAR[1].BegDtpObj := dtpIR_TtlToFundBeg;
  COLAObjAR[1].EndDtpObj := dtpIR_TtlToFundEnd;
  COLAObjAR[1].DataSrc := dtm.dtsFB;
  COLAObjAR[1].COLAEdtObj := edtIR_TtlToFundCOLA;
. . .

procedure TfrmMain.dtp_COLALineBegEndExit(Sender: TObject);
  I: Byte;
  FieldIDBy: Byte;
  YrCountBy: Byte;
      ///  Example of an event handler.  Call when user exits
      ///  either a begin date field or end date field component.
  FieldIDBy := 0;
      ///  Find the array index of the matching record
  for I := 1 to Length(COLAObjAR) do
    if (Sender = COLAObjAR[I].BegDtpObj) then
      FieldIDBy := 1;
    else if (Sender = COLAObjAR[I].EndDtpObj) then
      FieldIDBy := 2;
      ///  Now that the record containing the objects for this
      ///  set of components has been identified the validation
      ///  routines follow.
. . .

Open in new window

Geert GOracle dba
Top Expert 2009

well i actually have code, which uses 1 array to link a table to a editing form, grid, tabsheet, etc

for this i actually use a Form class

i define the name of the grid, and the name of the form editor class, filter class, etc

looks like you want to take this a step further
and define a template per form

if you have similar sets of components you could consider using a frame for the same set of editing components
you would only benefit from this if you have 5 or more of 1 set
otherwise it's not really worth the conversion
if you on the other hand have a basic set of a few components and similar but different behaviour,
you could think about deriving from those frames

for example:
A data range:
1: A start date with a TDateTimePicker to now

2: A start date with a TDateTimePicker
same for end date

3: A start date with a TDateTimePicker and checkbox for optional
,same for end date

if you create the first set with a Frame,
you can descend from that first Frame and add a second datetimepicker
the next descendant (or configuration) would show the checkboxes
you could then extend to allow for restricted dates (like non-holidays)

There are a lot of ways to reduce code, and visual form components and events
Depending on what you have now

The best thing for you would be to look at similar behaviour of items
and then try to group that behaviour
You could even create a Compound Component (Like TLabeledEdit)

It's allways outweighing the amount of work, with the benefits it will bring

I have no idea, how many common groups you have, but i think that grouping would be the first step
Off course, you need to know of different ways of bundling behaviour and code


I have 6 identical components set and 1 more nearly similar.  I can't believe that I hadn't remembered to consider frames!  I need to refresh my understanding of frames and then see if there is some way I can use them with the new grid that will also contain value sets as rows.

 "It's allways outweighing the amount of work, with the benefits it will bring": so true.   In this case I am still just trying to see the available options.



Thanks for the help on this broad question.  Your links were very useful.  My re-design is still coming together but the Gustavson article is proving particularly useful.  After significant past reading about patterns, the ideas are finally coming together with the help of this article.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial