kzaveri19 0 Posted July 18, 2020 (edited) Hello, I want to validate a value entered in a TDBGrid. The values I want to check are 'Close Amount Per' and 'Benchmark Close Per' (Field #4 and #5 below) based on the value of 'Long Short' (Field #1). The validation if whether the value is positive (Long) or negative (short). Below is a screenshot of the form. I am using the TField.OnValidate event as below for these these two fields: procedure TfrmClose.tbCloseAmtValidate(Sender: TField); var bkMark: TBookmark; begin if Sender = nil then exit else bkMark := sender.DataSet.GetBookmark; if (Sender.DataSet.FieldByName('Long Short').AsString = 'Long') then begin if (Sender.AsFloat < 0) then begin Sender.Clear; Sender.DataSet.Cancel; ShowMessage('Close value should be positive or zero'); end; end else if (Sender.DataSet.FieldByName('Long Short').AsString = 'Short') then begin if (Sender.AsFloat > 0) then begin Sender.Clear; Sender.DataSet.Cancel; ShowMessage('Close value should be negative or zero'); end; end; end; The issue is that the wrong value, while properly removed from the row being validated. The wrong value is posted to the row right below and an exception is thrown. See screenshots below Edited July 18, 2020 by kzaveri19 Share this post Link to post
Cristian Peța 103 Posted July 20, 2020 From the call stack it looks like Validate is called a little to late to modify the value. Documentation says also "To reject the current value of the field from the OnValidate event handler, raise an exception." I would use Abort like this: procedure TfrmClose.tbCloseAmtValidate(Sender: TField); begin if Sender = nil then exit if (Sender.DataSet.FieldByName('Long Short').AsString = 'Long') then begin if (Sender.AsFloat < 0) then begin ShowMessage('Close value should be positive or zero'); Abort; end; end else if (Sender.DataSet.FieldByName('Long Short').AsString = 'Short') then begin if (Sender.AsFloat > 0) then begin ShowMessage('Close value should be negative or zero'); Abort; end; end; end; Share this post Link to post
kzaveri19 0 Posted July 22, 2020 (edited) Hi Cristian, Thank you! How do I call it earlier? I am using the vanilla TDBGrid. I believe the OnValidate is triggered when I move the cursor to the next field or the cell below in the same field. I modified your code slightly as below: procedure TfrmClose.tbCloseAmtValidate(Sender: TField); begin if Sender = nil then exit; try if (Sender.DataSet.FieldByName('Long Short').AsString = 'Long') then begin if (Sender.AsFloat < 0) then begin ShowMessage('Close value should be positive or zero'); raise Exception.Create('Wrong value'); end; end else if (Sender.DataSet.FieldByName('Long Short').AsString = 'Short') then begin if (Sender.AsFloat > 0) then begin ShowMessage('Close value should be negative or zero'); raise Exception.Create('Wrong value'); end; end; except on E : Exception do begin if E.Message = 'Wrong value' then Abort; end; end; end; The cursor stays in the same field (which I want), the the DBGrid copies the value across all records. This is fixed if I correct the value, but looks weird. When the error is caught, cursor stays in the same cell, but wrong value displayed across all records When the correct value is entered, the DBGrid updates properly and everything works I'm just afraid about the problematic wrong value displayed when abort is called. Is there anyway to fix that? Thank you again Cristian. I am so glad I joined this group! Edited July 22, 2020 by kzaveri19 Share this post Link to post
Cristian Peța 103 Posted July 22, 2020 5 hours ago, kzaveri19 said: When the error is caught, cursor stays in the same cell, but wrong value displayed across all records I can't reproduce this issue (the wrong value to be displayed across all records). What Delphi version do you use? Try to do a minimal example to reproduce this and post here. 5 hours ago, kzaveri19 said: I modified your code slightly But why ?!? Your code is more convoluted and I don't see any benefit. Only trouble. Share this post Link to post