Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@ private static void LayoutAnchoredControls(IArrangedElement container)
continue;
}

if (UseAnchorLayoutV2(element) && GetAnchorInfo(element) is null)
{
UpdateAnchorInfoV2((Control)element, ignoreParentSuspendState: true);
}

Debug.Assert(GetAnchorInfo(element) is not null, "AnchorInfo should be initialized before LayoutAnchorControls().");
SetCachedBounds(element, GetAnchorDestination(element, displayRectangle, measureOnly: false));
}
Expand Down Expand Up @@ -823,7 +828,9 @@ private static void UpdateAnchorInfo(IArrangedElement element)
/// https://github.com/dotnet/winforms/blob/tree/main/docs/design/anchor-layout-changes-in-net80.md for more details.
/// Developers may opt-out of this new behavior using switch <see cref="AppContextSwitches.AnchorLayoutV2"/>.
/// </devdoc>
internal static void UpdateAnchorInfoV2(Control control)
internal static void UpdateAnchorInfoV2(Control control) => UpdateAnchorInfoV2(control, ignoreParentSuspendState: false);

private static void UpdateAnchorInfoV2(Control control, bool ignoreParentSuspendState)
{
if (!CommonProperties.GetNeedsAnchorLayout(control))
{
Expand All @@ -848,8 +855,9 @@ internal static void UpdateAnchorInfoV2(Control control)
// outside of serialized source and happen only in design-time scenario. Hence, checking for
// LayoutSuspendCount > 1.
bool ancestorInDesignMode = control.IsAncestorSiteInDesignMode;
if ((ancestorInDesignMode && parent.LayoutSuspendCount > 1)
|| (!ancestorInDesignMode && parent.LayoutSuspendCount != 0))
if (!ignoreParentSuspendState
&& ((ancestorInDesignMode && parent.LayoutSuspendCount > 1)
|| (!ancestorInDesignMode && parent.LayoutSuspendCount != 0)))
{
// Mark parent to indicate that one of its child control requires AnchorsInfo to be calculated.
parent._childControlsNeedAnchorLayout = true;
Expand Down
59 changes: 59 additions & 0 deletions src/test/integration/UIIntegrationTests/AnchorLayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,65 @@ public void ParentChanged_AnchorsUpdated()
}
}

[WinFormsFact]
public void AnchorLayoutV2_ReplaceParentWhileAncestorLayoutSuspended_AnchorsRemainConsistent()
{
// Regression test for https://github.com/dotnet/winforms/issues/14500
using AnchorLayoutV2Scope scope = new(enable: true);
using Form form = new() { ClientSize = new Size(400, 300) };
using Panel originalPanel = new()
{
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
Location = new Point(20, 30),
Size = new Size(100, 120)
};
using Panel replacementPanel = new();

form.Controls.Add(originalPanel);
form.ResumeLayout(performLayout: true);

form.ClientSize = new Size(500, 350);
Assert.Equal(new Rectangle(20, 30, 200, 170), originalPanel.Bounds);

ReplaceControl(originalPanel, replacementPanel);
Assert.Equal(originalPanel.Anchor, replacementPanel.Anchor);
Assert.Equal(new Rectangle(20, 30, 200, 170), replacementPanel.Bounds);

form.ClientSize = new Size(600, 400);
Assert.Equal(new Rectangle(20, 30, 300, 220), replacementPanel.Bounds);

static void ReplaceControl(Control controlToRemove, Control controlToAdd)
{
controlToRemove.SuspendLayout();
controlToAdd.SuspendLayout();
controlToAdd.Anchor = controlToRemove.Anchor;
controlToAdd.Dock = controlToRemove.Dock;
controlToAdd.Location = controlToRemove.Location;
controlToAdd.Size = controlToRemove.Size;
controlToRemove.ResumeLayout(true);
controlToAdd.ResumeLayout(true);

Control parentOfControlToRemove = controlToRemove.Parent!;
Control? parentOfControlToAdd = controlToAdd.Parent;
int index = parentOfControlToRemove.Controls.IndexOf(controlToRemove);
parentOfControlToRemove.SuspendLayout();
if (parentOfControlToAdd is { } parentToSuspend)
{
parentToSuspend.SuspendLayout();
}

parentOfControlToRemove.Controls.Remove(controlToRemove);
parentOfControlToRemove.Controls.Add(controlToAdd);
parentOfControlToRemove.Controls.SetChildIndex(controlToAdd, index);
parentOfControlToRemove.ResumeLayout(true);

if (parentOfControlToAdd is { } parentToResume)
{
parentToResume.ResumeLayout(true);
}
}
}

[WinFormsFact]
public void SetBoundsOnAnchoredControl_BoundsChanged()
{
Expand Down
Loading