Es stellte sich heraus, dass die Funktion, die alles UpdateAnchorRules
ist bricht. TControl
speichert FOriginalParentSize
und seine eigene Originalgröße in FAnchorRules
, und verwendet, um die Größe automatisch als Elterngrößen zu ändern. UpdateAnchorRules()
nimmt aktuelle übergeordnete Größe und aktuelle Kontrolle Width
und Height
und speichert diese in FOriginalParentSize
und FAnchorRules
.
Wenn alles ordnungsgemäß funktionierte, hätte das bei normalen Größenanpassungen keine Auswirkungen, da das Steuerelement und die übergeordneten Elemente die Größe ändern.
Aber wenn das Steuerelement Width
ist weniger als Null aufgrund der Verankerung, Windows und folglich Delphi immer noch es 0
. Wenn UpdateAnchorRules
an diesem Punkt aufgerufen wird, wird der falsche, nicht übereinstimmende 0
Wert für die ursprüngliche Breite gespeichert. Danach ist das Layout nicht mehr zu reparieren.
(Wenn es nicht genannt wird, Width
weiterhin in der richtigen Beziehung zu Eltern Width
aufgrund ursprünglichen Größen erhalten aktualisiert werden)
Stellt sich etwas aus der Griff erstellen ein Fenster beinhaltet ruft UpdateAnchorRules
zweimal: zuerst in WinAPI CreateWindow
wie es Versendet WM_SIZE
vor der Rückgabe (und WM_SIZE
Handler ruft UpdateAnchorRules
), und zweitens explizit in CreateHandle
nach der Erstellung von Handle.
Es scheint so lange, wie wir UpdateAnchorRules
für die Dauer von CreateHandle
deaktivieren können, werden wir erfolgreich sein. Aber es gibt explizite Aufrufe an UpdateAnchorRules
in CreateHandle
, was bedeutet, dass jemand dachte, benötigt, um eine Anpassung der Anchor-Regeln nach der Erstellung von Handle zu sein.
Also vielleicht fehlt mir etwas, und wenn ich es deaktiviere, wird etwas kaputt gehen?
In jedem Fall gibt es zwei Möglichkeiten, UpdateAnchorRules
zu deaktivieren: FAnchorMove
oder csLoading
zu setzen. Der erste ist nicht gut, weil es Code gibt, der es in der Mitte durch RecreateWnd
löscht und dann UpdateAnchorRules
erneut aufruft.
Zweite man arbeitet und hier ist eine Lösung:
type
TComponentHack = class helper for TComponent
public
procedure SetCsLoading(Value: boolean);
end;
procedure TComponentHack.SetCsLoading(Value: boolean);
var i: integer;
begin
if Value then
Self.FComponentState := Self.FComponentState + [csLoading]
else
Self.FComponentState := Self.FComponentState - [csLoading];
for i := 0 to Self.ComponentCount-1 do
if Self.Components[i] is TControl then
TControl(Self.Components[i]).SetCsLoading(Value);
end;
procedure SafeRecreateWnd();
begin
MyControl.SetCsLoading(true);
try
MyControl.RecreateWnd(); //or any operation which triggers it -- such as docking or making the window visible first time after RecreateWnd()
finally
MyControl.SetCsLoading(false);
end;
end;
Haftungsausschluss:
Ich habe keine Ahnung, was sonst durch Ausführen TControl
Operationen mit csLoading Satz gebrochen werden.
bessere Alternative wäre UpdateAnchorRules
Verfahren Haken und andere Flagprüfung speziell für diesen Zweck hinzufügen, aber das würde erfordern entweder Neuimplementierung UpdateAnchorRules
vollständig (anfällig für verschiedene Versionen von Delphi mit verschiedenen Originalen UpdateAnchorRules
zu brechen) oder zu erfinden, einen Weg Rufen Sie das Original UpdateAnchorRules
an, das normalerweise zerstört wird, indem Sie es mit einem Haken umschreiben.
"Unmöglich zu verwenden" ist ein bisschen übertrieben, denke ich. Viele Anwendungsfälle, in denen das Handle des Formulars nie neu erstellt wird. –
Ich glaube nicht. Selbst wenn Sie es jetzt scheinbar nicht tun, einen Monat später tun Sie etwas, das neu erstellt und knallt, Sie haben Bugs eingeführt, ohne es zu wissen. Anker sind unberechenbar. – himself
Hmm ja, sicher, deshalb werden sie so oft benutzt ... Anker funktionieren ziemlich gut und haben das für mich und viele andere seit Jahren getan. Anscheinend ist Ihre Laufleistung anders, aber Ihre Unfähigkeit, sie zu benutzen, macht sie nicht unmöglich für alle anderen zu benutzen. –