asd-tm
asd-tm

Reputation: 5238

How to update dataset fields' values using the changed data in user defined FMX TGrid coumns

I use the following way to define and populate a column with TCalendarEdit ancessor cells (here is the interface part). Let me know if I need to expose implementation.

    type 
      TDynamicRecord = record
        Field1, Field2, Field3: string;
        DateSBU: TDate;
        TimeSBU: TTime;
      end;

      TDateCell = class(TCalendarEdit)
      protected
        procedure SetData(const Value: TValue); override;
      public
        constructor Create(AOwner: TComponent); override;
      end;

      TDateColumn = class(TColumn)
      protected
        function CreateCellControl: TStyledControl; override;
      public
        constructor Create(AOwner: TComponent); override;
      end;

The code works fine and the column of type TDateColumn can be added to the grid.

I asked a question and opened a bounty for it looking for a technique to populate the user defined column by LiveBindings but I have got no answers by the bounty expiry date. That is why now I am trying another way. I declare a collection DynamicData: TList<TDynamicRecord>; and populate it from the dataset. This approach is quite clearly explained in the answer of @Mike-Sutton and in his blog. I have managed to do this. The data is displayed properly in the grid and in its newly defined columns.

But now I am stuck with the other problem. I need to update dataset on user activities. I tried the OnSetValue and OnEditingDone events of the parent grid (according to the documentation these event are to be used for data updates) but strangely it does not fire.

What will be the proper event or other way suitable for updating the dataset?

Upvotes: 1

Views: 1399

Answers (1)

asd-tm
asd-tm

Reputation: 5238

I think that the issue is, at least partially, resolved.

It was necessary to redeclare almost all the classes. I would be glad if someone gives me an advice how to reduce the complecity of the code.

I had to declare this class to expose FOnEditingDone and procedure SetValue(...) making them accessible:

type  
  TDynamicCustomGrid = class(TGrid)
  private
    FOnEditingDone: TOnEditingDone;
  protected
    procedure SetValue(Col, Row: Integer; const Value: TValue);override;
  end;
implementation
  procedure TDynamicCustomGrid.SetValue(Col, Row: Integer; const Value: TValue);
  begin
    inherited;
  end;

Then I redeclared

type  
  TDateColumn = class(TColumn)
  protected
    ...
    function Grid: TDynamicCustomGrid; overload;
    procedure DoDateChanged(Sender: TObject);
  public
    ...
  end;
implementation
procedure TDateColumn.DoDateChanged(Sender: TObject);
var
  P: TPointF;
  LGrid: TDynamicCustomGrid;
begin
  LGrid := Grid;
  if not Assigned(LGrid) then
    Exit;
  if FUpdateColumn then
    Exit;
  if FDisableChange then
    Exit;
  P := StringToPoint(TFmxObject(Sender).TagString);
  LGrid.SetValue(Trunc(P.X), Trunc(P.Y), TStyledControl(Sender).Data);
  if Assigned(LGrid.FOnEditingDone) then
    LGrid.FOnEditingDone(Grid, Trunc(P.X), Trunc(P.Y));
end;

function TDateColumn.Grid: TDynamicCustomGrid;
var
  P: TFmxObject;
begin
  Result := nil;
  P := Parent;
  while Assigned(P) do
  begin
    if P is TCustomGrid then
    begin
      Result := TDynamicCustomGrid(P);
      Exit;
    end;
    P := P.Parent;
  end;
end;

And finally I assigned TDateCell(Result).OnChange := DoDateChanged; in function TDateColumn.CreateCellControl: TStyledControl;

I am far from thinking that this way is optimal and will be grateful for any comments and ideas how to optimize the code.

Upvotes: 0

Related Questions