Reputation: 5238
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
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