0

I am stuck a bit. My aim is to check and validate my currency field always when it's value changed never mind from the inline code or from the user interface. Is there any validation pattern or sample for it? I want to avaiod calling my validation procedure twice.

Any help or advice would be greatly appreciated.

Here is my example:

type
TMyForm = class(TForm)   
  ceMyCurrencyEdit: TcxCurrencyEdit;
  procedure FormShow(Sender: TObject);
private
{ Private declarations }
  procedure SetupMyForm;
public
{ Public declarations }
  procedure ValidateMyCurrencyValue;
  function IsValidCurrency: Boolean;
end; 

procedure TMyForm.ValidateMyCurrencyField;
begin
  if not IsValidCurrency then
  begin
    WarningDlg(
       Format(
           'InValid value in field: [%s..%s]',
           [Formatfloat(ceMyCurrencyEditDisplayFormat, ceMyCurrencyEdit.MinValue),
           Formatfloat(ceMyCurrencyEdit.DisplayFormat, ceMyCurrencyEdit.MaxValue)]
        )
    );
    ceMyCurrencyEdit.Value := ceMyCurrencyEdit.MinValue; 
  end;   
end;

function TMyForm.IsValidCurrency: Boolean;
begin
  Result := (ceMyCurrencyEdit.Value >= ceMyCurrencyEdit.MinValue) and (ceMyCurrencyEdit.Value <= ceMyCurrencyEdit.MaxValue);  
end;

procedure TMyForm.SetupMyForm;
begin
  //MaxValue is 100
  ceMyCurrencyEdit.Value := 102;
  //At this point I need to call ValidateMyCurrencyField to get warning msg and refuse its value
  ValidateMyCurrencyField;
end;

procedure TMyForm.FormShow(Sender: TObject);
begin
  SetupMyForm;
end;

procedure TMyForm.ceMyCurrencyEditPropertiesEditValueChanged(Sender: TObject);
begin
  ValidateMyCurrencyField;
end;

What I want is...

Thanks for the answers!

Steve88
  • 2,366
  • 3
  • 24
  • 43
  • DevEx editors often have an `OnValidate` event in their `Properties` property. This is invoked on user changes normally, but can also directly be invoked by calling `ValidateEdit` on the editor. – nil Feb 18 '19 at 17:12
  • What is use is just a sample control and from the code it will not fired. What I want is totally control dependent, but thanks. – Steve88 Feb 18 '19 at 17:49

1 Answers1

1

I'm not sure why you seemed a bit dismissive os @Nil's suggestion, but below is an example project which shows using the cxCurrencyEdit's validation facility and using an interposer TcxCurrencyEdit class to record the result of the validation process in its ValidationState property.

Obviously you could use the ValidationState property to avoid repeating your validation process or indeed doing it at all if the state says it's valid. However, performance-wise, I very much doubt that you'd be saving yourself anything.

Obviously, the point of the interposer class is to record the validation state of the control so that you can avoid validating it a second time. Whether you use it in combination with the cxCurrencyEdit1PropertiesValidate event is entirely up to you.

I leave you to weave this in with your existing code.

Btw, the TEdit control is just there to allow focus to be shifted from the cxCurrencyEdit to trigger its cxCurrencyEdit1PropertiesValidate event.

UpdateYou asked in a comment about validating a value which is set in code. With an interposer class, it's easy to add a Getter and Setter for the Value property and do the validation in the Setter - see `SetValue below,

  type
    TCurrencyValidation = (cvNotDone, cvOK, cvInvalid);

    TcxCurrencyEdit = class(cxCurrencyEdit.TcxCurrencyEdit)
    private
      FValidationState : TCurrencyValidation;
      function GetValue: Double;
      procedure SetValue(const AValue: Double);
    protected
      property ValidationState : TCurrencyValidation read FValidationState write FValidationState;
    published
      property Value : Double read GetValue write SetValue;
    end;

    TForm1 = class(TForm)
      cxCurrencyEdit1: TcxCurrencyEdit;
      Edit1: TEdit;
      procedure FormCreate(Sender: TObject);
      procedure cxCurrencyEdit1PropertiesChange(Sender: TObject);
      procedure cxCurrencyEdit1PropertiesValidate(Sender: TObject;
        var DisplayValue: Variant; var ErrorText: TCaption;
        var Error: Boolean);
    end;

  procedure TForm1.FormCreate(Sender: TObject);
  begin
    cxCurrencyEdit1.Properties.MinValue := 5;
    cxCurrencyEdit1.Properties.MaxValue := 10;
    cxCurrencyEdit1.Value := 8;
  end;

  procedure TForm1.cxCurrencyEdit1PropertiesChange(Sender: TObject);
  begin
    TcxCurrencyEdit(Sender).ValidationState := cvNotDone;
  end;

  procedure TForm1.cxCurrencyEdit1PropertiesValidate(Sender: TObject;
    var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
  var
    Min,
    Max : Double;
  begin
    Min := TcxCurrencyEdit(Sender).Properties.MinValue;
    Max := TcxCurrencyEdit(Sender).Properties.MaxValue;
    if (DisplayValue >= Min) and (DisplayValue <= Max) then
      TcxCurrencyEdit(Sender).ValidationState := cvOK
    else
      TcxCurrencyEdit(Sender).ValidationState := cvInvalid;
    Error := not (TcxCurrencyEdit(Sender).ValidationState = cvOK);
    if Error then
      ErrorText := 'InvalidValue';
  end;

  function TcxCurrencyEdit.GetValue: Double;
  begin
    Result := inherited Value;
  end;

  procedure TcxCurrencyEdit.SetValue(const AValue: Double);
  begin
    //  insert code to validate AValue here
    inherited Value := AValue;
  end;
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • Really nice solution! Big thanks for it! But the inline code side is not solved yet, what if I want to set a default value after I setted the min - max value.There are no event which validate it. (The part in my setupform procedure) – Steve88 Feb 18 '19 at 19:00
  • See update - the way to do it is to write a new property setter for thr `Value` property. – MartynA Feb 18 '19 at 19:19