diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs index 90eeab9368b..766c40d952d 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.Modern.cs @@ -654,12 +654,23 @@ protected override void OnVisualStylesModeChanged(EventArgs e) ResetComboAdapter(); ResetHeightCache(); + bool recreateSystemHandle = FlatStyle == FlatStyle.System + && IsHandleCreated; + // Crossing the modern/classic boundary is reported as VisualStylesModeChangeImpact.Recreate // (see GetVisualStylesModeChangeImpact), so the base recreates the handle here. That is the // only clean way to unwind the modern native-window state (the WM_NCCALCSIZE client // expansion and the per-handle modern baseline); a fresh classic handle then behaves exactly // as before, and a fresh modern handle captures a clean baseline. + // FlatStyle.System stays native, but an existing native handle still needs a rebuild when + // visual-style mode changes to avoid stale geometry in designer/runtime transitions. base.OnVisualStylesModeChanged(e); + + if (recreateSystemHandle && IsHandleCreated) + { + RecreateHandle(); + } + ApplyModernComboLayout(); RefreshModernDropDownCornerPreference(); } diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs index 3fe91f3fd09..fca5b5c33ef 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ComboBox/ComboBox.cs @@ -530,15 +530,25 @@ public partial FlatStyle FlatStyle return; } - bool usedModernMetrics = UsesModernComboAdapter; + bool previousUsesModernMetrics = UsesModernComboAdapter; _flatStyle = value; ResetComboAdapter(); - if (usedModernMetrics != UsesModernComboAdapter) + bool currentUsesModernMetrics = UsesModernComboAdapter; + + if (previousUsesModernMetrics != currentUsesModernMetrics) { ResetHeightCache(); CommonProperties.xClearPreferredSizeCache(this); - ApplyModernComboLayout(); + + if (IsHandleCreated) + { + RecreateHandle(); + } + else + { + ApplyModernComboLayout(); + } LayoutTransaction.DoLayout( this, @@ -553,8 +563,11 @@ public partial FlatStyle FlatStyle PropertyNames.FlatStyle); } } + else + { + ApplyModernComboLayout(); + } - ApplyModernComboLayout(); RefreshModernDropDownCornerPreference(); Invalidate(); } diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs index 2af7ac2f04d..a9477200bc6 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ComboBoxTests.cs @@ -287,6 +287,64 @@ public void ComboBox_ModernVisualStyles_SystemModeChangeDoesNotRequestLayout() Assert.False(control.IsHandleCreated); } + [WinFormsFact] + public void ComboBox_ModernVisualStyles_FlatStyleTransitionToSystem_RecreatesHandle() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using Panel parent = new(); + using VisualStylesComboBox control = new() + { + FlatStyle = FlatStyle.Standard, + VisualStylesMode = VisualStylesMode.Net11 + }; + parent.Controls.Add(control); + parent.CreateControl(); + control.CreateControl(); + + int handleCreatedCallCount = 0; + int handleDestroyedCallCount = 0; + control.HandleCreated += (sender, e) => handleCreatedCallCount++; + control.HandleDestroyed += (sender, e) => handleDestroyedCallCount++; + + control.FlatStyle = FlatStyle.System; + + Assert.True(control.IsHandleCreated); + Assert.Equal(1, handleDestroyedCallCount); + Assert.Equal(1, handleCreatedCallCount); + Assert.IsType(control.CreateAdapter()); + } + + [WinFormsFact] + public void ComboBox_ModernVisualStyles_SystemModeBoundaryChangeWithHandle_RecreatesHandle() + { + using SystemVisualSettingsTestScope settingsScope = new( + clientAreaAnimationEnabled: false, + highContrastEnabled: false); + using Panel parent = new(); + using VisualStylesComboBox control = new() + { + FlatStyle = FlatStyle.System, + VisualStylesMode = VisualStylesMode.Classic + }; + parent.Controls.Add(control); + parent.CreateControl(); + control.CreateControl(); + + int handleCreatedCallCount = 0; + int handleDestroyedCallCount = 0; + control.HandleCreated += (sender, e) => handleCreatedCallCount++; + control.HandleDestroyed += (sender, e) => handleDestroyedCallCount++; + + control.VisualStylesMode = VisualStylesMode.Net11; + + Assert.True(control.IsHandleCreated); + Assert.Equal(1, handleDestroyedCallCount); + Assert.Equal(1, handleCreatedCallCount); + Assert.IsType(control.CreateAdapter()); + } + [WinFormsFact] public void ComboBox_ModernVisualStyles_ModeChangeRemeasuresAutoSizeRow() {