BeginUpdate/Endupdate block with add or remove of child objects : misconception in delphi?

  

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 …

Comments are closed.