diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ContainerControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ContainerControl.cs index a13540a8153..0f869f200df 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ContainerControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ContainerControl.cs @@ -48,6 +48,11 @@ public class ContainerControl : ScrollableControl, IContainerControl /// private bool _isScaledByDpiChangedEvent; + /// + /// Indicates scaling, due to DPI changed event, of the container control is in progress. + /// + internal bool _dpiScalingInProgress; + private BitVector32 _state; /// @@ -1441,6 +1446,8 @@ internal void ScaleContainerForDpi(int deviceDpiNew, int deviceDpiOld, Rectangle SuspendAllLayout(this); try { + _dpiScalingInProgress = true; + if (LocalAppContextSwitches.ScaleTopLevelFormMinMaxSizeForDpi) { // The suggested rectangle comes from Windows, and it does not match with our calculations for scaling controls by AutoscaleFactor. @@ -1491,6 +1498,9 @@ internal void ScaleContainerForDpi(int deviceDpiNew, int deviceDpiOld, Rectangle // We want to perform layout for dpi-changed high Dpi improvements - setting the second parameter to 'true' ResumeAllLayout(this, true); _isScaledByDpiChangedEvent = false; + + // Scaling and ResumeLayout, due to DPI changed event, should be finished by now for this container. + _dpiScalingInProgress = false; } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index e775a900808..218177a9726 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -1713,10 +1713,10 @@ internal bool IsTopMdiWindowClosing } /// - /// returns bool indicating whether the control is currently being scaled. + /// Returns bool indicating whether the control is currently being scaled. /// This property is set in ScaleControl method to allow method being called to condition code that should not run for scaling. /// - internal bool IsCurrentlyBeingScaled + internal bool ScalingInProgress { get => GetExtendedState(ExtendedStates.CurrentlyBeingScaled); private set => SetExtendedState(ExtendedStates.CurrentlyBeingScaled, value); @@ -10450,7 +10450,7 @@ internal void ScaleControl(SizeF includedFactor, SizeF excludedFactor, Control r { try { - IsCurrentlyBeingScaled = true; + ScalingInProgress = true; BoundsSpecified includedSpecified = BoundsSpecified.None; BoundsSpecified excludedSpecified = BoundsSpecified.None; @@ -10489,7 +10489,7 @@ internal void ScaleControl(SizeF includedFactor, SizeF excludedFactor, Control r } finally { - IsCurrentlyBeingScaled = false; + ScalingInProgress = false; } } @@ -10589,9 +10589,6 @@ protected virtual void ScaleControl(SizeF factor, BoundsSpecified specified) scaledSize = LayoutUtils.UnionSizes(scaledSize, minSize); if (DpiHelper.IsScalingRequirementMet - // In the v2 layout, anchors are updated/computed after the controls bounds changed - // and, thus, don't need scaling. - && !DefaultLayout.UseAnchorLayoutV2(this) && ParentInternal is { } parent && (parent.LayoutEngine == DefaultLayout.Instance)) { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/DefaultLayout.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/DefaultLayout.cs index d443d5e939a..57652becf62 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Layout/DefaultLayout.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Layout/DefaultLayout.cs @@ -896,6 +896,12 @@ internal static void UpdateAnchorInfoV2(Control control) return; } + // Anchors are already scaled for the new DPI. + if (DpiScalingInProgress(control, parent)) + { + return; + } + AnchorInfo anchorInfo = GetAnchorInfo(control); if (anchorInfo is null) { @@ -913,6 +919,28 @@ internal static void UpdateAnchorInfoV2(Control control) anchorInfo.Right = displayRect.Width - (x + elementBounds.Width); anchorInfo.Bottom = displayRect.Height - (y + elementBounds.Height); + + // Walk through parent hierarchy and check if scaling due to DPI change is in progress. + static bool DpiScalingInProgress(Control control, Control parent) + { + if (control.ScalingInProgress + || (control is ContainerControl container && container._dpiScalingInProgress)) + { + return true; + } + + while (parent is not null) + { + if (parent is ContainerControl parentContainer && parentContainer._dpiScalingInProgress) + { + return true; + } + + parent = parent.Parent; + } + + return false; + } } public static AnchorStyles GetAnchor(IArrangedElement element) => CommonProperties.xGetAnchor(element); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/MonthCalendar.cs b/src/System.Windows.Forms/src/System/Windows/Forms/MonthCalendar.cs index af97449b594..b624f03b7ff 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/MonthCalendar.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/MonthCalendar.cs @@ -1756,7 +1756,7 @@ protected override void SetBoundsCore(int x, int y, int width, int height, Bound // Second argument to GetPreferredWidth and GetPreferredHeight is a boolean specifying if we should update the number of rows/columns. // We only want to update the number of rows/columns if we are not currently being scaled. - bool updateRowsAndColumns = !DpiHelper.IsScalingRequirementMet || !IsCurrentlyBeingScaled; + bool updateRowsAndColumns = !DpiHelper.IsScalingRequirementMet || !ScalingInProgress; if (width != oldBounds.Width) {