This question follow this one: Why this change in tokyo 10.2.3? and introduce what i think is a misconception in delphi
Basically in firemonkey you have the methods BeginUpdate
and EndUpdate
that permit you to deactivate/activate the realign
of a control when you update it. Instead of realigning several time the control every time you change one of it's properties, you do it only one time at the end when you call EndUpdate
below the implementation of those functions:
procedure TControl.BeginUpdate;
var
I: Integer;
begin
if FUpdating = 0 then
DoBeginUpdate;
Inc(FUpdating);
if FControls <> nil then
for I := 0 to FControls.Count - 1 do
FControls[I].BeginUpdate;
end;
procedure TControl.EndUpdate;
var
I: Integer;
begin
if IsUpdating then
begin
if FControls <> nil then
for I := 0 to FControls.Count - 1 do
FControls[I].EndUpdate;
Dec(FUpdating);
if not IsUpdating then
begin
DoEndUpdate;
RefreshInheritedCursorForChildren;
end;
end;
end;
procedure TControl.DoBeginUpdate;
begin
end;
procedure TControl.DoEndUpdate;
begin
Realign;
end;
note (it's important) those functions are VIRTUAL, so you can override
their behavior, like what TGrid did :
procedure TCustomGrid.DoBeginUpdate;
begin
if Model <> nil then
Model.BeginUpdate;
inherited;
end;
procedure TCustomGrid.DoEndUpdate;
begin
inherited;
if Model <> nil then
Model.EndUpdate;
end;
OK now the problem, and i think it's a misconception, when you update the properties of a control inside a BeginUpdate
/EndUpdate
block, often you also add some child controls (or remove some). the problem is the way the procedure TControl.DoAddObject(const AObject: TFmxObject);
and procedure TControl.DoRemoveObject(const AObject: TFmxObject);
are implemented, to resume
procedure TControl.DoAddObject(const AObject: TFmxObject);
begin
...
if AObject is TControl then
begin
AsControl := TControl(AObject);
AsControl.FUpdating := FUpdating;
end
...
end;
and
procedure TControl.DoRemoveObject(const AObject: TFmxObject);
procedure ResetUpdatingState(const AObject: TFmxObject);
var
I: Integer;
begin
if AObject is TControl then
TControl(AObject).FUpdating := 0;
for I := 0 to AObject.ChildrenCount - 1 do
ResetUpdatingState(AObject.Children[I]);
end;
begin
....
ResetUpdatingState(AObject);
....
end;
as you understand, when you add a child to a control then you set it's FUpdating
to the same value of the new parent control (and you also don't fire any BeginUpdate
/EndUpdate
event so what happen with control like Tgrid?). you are not touching the FUpdating
of the childs of this child control leaving them in an highly probably wrong state
when you remove a child control, then you set it's FUpdating
to zero, and same for all it's childs (so different behavior than when you add). but here also you don't fire any BeginUpdate
/EndUpdate
event
So is this a misconception or is there any reason to do it like that?
I think a good way must be to do :
procedure TControl.DoAddObject(const AObject: TFmxObject);
begin
...
if AObject is TControl then
For i := 1 to FUpdating do
TControl(AObject).BeginUpdate;
...
end;
and
procedure TControl.DoRemoveObject(const AObject: TFmxObject);
begin
....
if AObject is TControl then
For i := 1 to FUpdating do
TControl(AObject).EndUpdate;
....
end;
But not sure if I didn't miss something ...