Search code examples
delphievent-handlingtclientdatasetdbgrid

How to detect user either in DBGrid or ClientDataset has deleted data in a cell at runtime?


I have a procedure that needs to be triggered/fired by a user deletion of data in a cell. Looks like ClientDataset.Delete is not appropriate for this case.

My data structure are:

TADOConnection -> TADOQuery -> TDataSetProvider -> TClientDataSet -> TDataSource -> TDBGRidEh (descendant of TDBGrid)

Do I need to create a procedure to detect the deletion or is there already an event or properties ready to use for this purpose?


Solution

  • The code below should detect when a given field - Customer in this example - of your CDS has been modified so that either its AsString property is an empty string or the Field's value has been set to Null, but, in either case, only if the Field had a non-Null, non-empty value previously.

    It uses a custom descendant of a TFieldDataLink to do the detection and handle the dsFieldChange event. This will only fire immediately while the Post method is executing and has not yet returned.

    type
      TMyFieldDataLink = class(TFieldDataLink)
        procedure DataEvent(Event: TDataEvent; Info: Integer); override;
      end;
    
    type
      TForm1 = class(TForm)
        ClientDataSet1: TClientDataSet;
        DataSource1: TDataSource;
        DBGrid1: TDBGrid;
        ADOConnection1: TADOConnection;
        ADOQuery1: TADOQuery;
        DataSetProvider1: TDataSetProvider;
        DBNavigator1: TDBNavigator;
        DBEdit1: TDBEdit;
        procedure FormCreate(Sender: TObject);
      private
        FieldDataLink : TFieldDataLink;
      end;
    [...]
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FieldDataLink := TMyFieldDataLink.Create;
      FieldDataLink.DataSource := DataSource1;
      FieldDataLink.FieldName := 'Company';
    end;
    
    { TMyFieldDataLink }
    
    procedure TMyFieldDataLink.DataEvent(Event: TDataEvent; Info: Integer);
    var
      S : String;
      V : Variant;
    begin
      inherited;
    
      if Event = deFieldChange then begin
        V :=  Field.OldValue;
        if not VarIsNull(V) then begin
          S := V;
          if (S <> '') and (Field <> Nil) and (Field.IsNull or (Field.AsString = '')) then begin
            ShowMessage('Field: ' + Field.FieldName + ' emptied');
          end;
        end;
      end;
    end;
    

    To use, cut & paste into a new VCL project.

    Btw, for a problem like this, it's best to start by looking at it from the point of view of the dataset rather than a particular component like a DBGrid.