diff --git a/src/System.Windows.Forms/PublicAPI.Unshipped.txt b/src/System.Windows.Forms/PublicAPI.Unshipped.txt index fd3fe1e230a..70f934d430e 100644 --- a/src/System.Windows.Forms/PublicAPI.Unshipped.txt +++ b/src/System.Windows.Forms/PublicAPI.Unshipped.txt @@ -101,6 +101,7 @@ override System.Windows.Forms.RadioButton.OnPaint(System.Windows.Forms.PaintEven override System.Windows.Forms.RadioButton.OnSystemColorsChanged(System.EventArgs! e) -> void override System.Windows.Forms.RadioButton.OnVisualStylesModeChanged(System.EventArgs! e) -> void override System.Windows.Forms.UpDownBase.OnVisualStylesModeChanged(System.EventArgs! e) -> void +override System.Windows.Forms.ToolStripControlHost.OnOwnerChanged(System.EventArgs! e) -> void static System.Windows.Forms.Application.DefaultVisualStylesMode.get -> System.Windows.Forms.VisualStylesMode static System.Windows.Forms.Application.SetDefaultVisualStylesMode(System.Windows.Forms.VisualStylesMode styleSetting) -> void virtual System.Windows.Forms.Control.DefaultVisualStylesMode.get -> System.Windows.Forms.VisualStylesMode diff --git a/src/System.Windows.Forms/System/Windows/Forms/Control.VisualStylesMode.Docs.cs b/src/System.Windows.Forms/System/Windows/Forms/Control.VisualStylesMode.Docs.cs index 4354c55bc36..7d64a502591 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Control.VisualStylesMode.Docs.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Control.VisualStylesMode.Docs.cs @@ -27,6 +27,9 @@ public partial class Control /// shrink slightly. Prefer or for adaptive layouts. /// /// + /// This setting is not applied to controls hosted through . + /// + /// /// High Contrast resolves the effective mode to classic rendering. See the /// /// .NET 11 VisualStyles layout guidance for migration patterns. diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripControlHost.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripControlHost.cs index 7842c46d9ed..ea629788291 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripControlHost.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/ToolStrips/ToolStripControlHost.cs @@ -17,6 +17,9 @@ public partial class ToolStripControlHost : ToolStripItem private int _suspendSyncSizeCount; private ContentAlignment _controlAlign = ContentAlignment.MiddleCenter; private bool _inSetVisibleCore; + private bool _isUpdatingHostedControlVisualStylesMode; + private bool _hostedControlVisualStylesModeForced; + private VisualStylesMode _hostedControlVisualStylesModeBeforeForce = VisualStylesMode.Inherit; internal static readonly object s_gotFocusEvent = new(); internal static readonly object s_lostFocusEvent = new(); @@ -576,6 +579,16 @@ private void HandleResize(object? sender, EventArgs e) private void HandleTextChanged(object? sender, EventArgs e) => OnTextChanged(e); + private void HandleVisualStylesModeChanged(object? sender, EventArgs e) + { + if (_isUpdatingHostedControlVisualStylesMode) + { + return; + } + + ApplyHostedControlVisualStylesModePolicy(); + } + private void HandleControlVisibleChanged(object? sender, EventArgs e) { // check the STATE_VISIBLE flag rather than using Control.Visible. @@ -684,6 +697,8 @@ protected override void OnParentChanged(ToolStrip? oldParent, ToolStrip? newPare { if (oldParent is not null && Owner is null && newParent is null && _control is not null) { + RestoreHostedControlVisualStylesMode(); + // if we've really been removed from the item collection, // politely remove ourselves from the control collection ReadOnlyControlCollection? oldControlCollection @@ -698,6 +713,20 @@ protected override void OnParentChanged(ToolStrip? oldParent, ToolStrip? newPare base.OnParentChanged(oldParent, newParent); } + protected override void OnOwnerChanged(EventArgs e) + { + base.OnOwnerChanged(e); + + if (Owner is null) + { + RestoreHostedControlVisualStylesMode(); + } + else + { + ApplyHostedControlVisualStylesModePolicy(); + } + } + /// /// The events from the hosted control are subscribed here. /// Override to add/prevent syncing of control events. @@ -739,6 +768,7 @@ protected virtual void OnSubscribeControlEvents(Control? control) control.RightToLeftChanged += HandleRightToLeftChanged; control.TextChanged += HandleTextChanged; control.VisibleChanged += HandleControlVisibleChanged; + control.VisualStylesModeChanged += HandleVisualStylesModeChanged; control.Validating += HandleValidating; control.Validated += HandleValidated; } @@ -784,6 +814,7 @@ protected virtual void OnUnsubscribeControlEvents(Control? control) control.RightToLeftChanged -= HandleRightToLeftChanged; control.TextChanged -= HandleTextChanged; control.VisibleChanged -= HandleControlVisibleChanged; + control.VisualStylesModeChanged -= HandleVisualStylesModeChanged; control.Validating -= HandleValidating; control.Validated -= HandleValidated; } @@ -803,6 +834,52 @@ private void SyncControlParent() { ReadOnlyControlCollection? newControls = GetControlCollection(ParentInternal); newControls?.AddInternal(_control); + ApplyHostedControlVisualStylesModePolicy(); + } + + private bool ShouldForceHostedControlClassicVisualStylesMode() + => Owner is not null; + + private void ApplyHostedControlVisualStylesModePolicy() + { + if (_control is null || !ShouldForceHostedControlClassicVisualStylesMode()) + { + return; + } + + VisualStylesMode mode = _control.VisualStylesMode; + if (mode is VisualStylesMode.Classic or VisualStylesMode.Disabled) + { + return; + } + + _hostedControlVisualStylesModeBeforeForce = mode; + _hostedControlVisualStylesModeForced = true; + UpdateHostedControlVisualStylesMode(VisualStylesMode.Classic); + } + + private void RestoreHostedControlVisualStylesMode() + { + if (!_hostedControlVisualStylesModeForced || _control is null) + { + return; + } + + UpdateHostedControlVisualStylesMode(_hostedControlVisualStylesModeBeforeForce); + _hostedControlVisualStylesModeForced = false; + } + + private void UpdateHostedControlVisualStylesMode(VisualStylesMode mode) + { + _isUpdatingHostedControlVisualStylesMode = true; + try + { + _control.VisualStylesMode = mode; + } + finally + { + _isUpdatingHostedControlVisualStylesMode = false; + } } protected virtual void OnHostedControlResize(EventArgs e) diff --git a/src/System.Windows.Forms/System/Windows/Forms/VisualStylesMode.cs b/src/System.Windows.Forms/System/Windows/Forms/VisualStylesMode.cs index e38e19d9d9b..a75eedaab2d 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/VisualStylesMode.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/VisualStylesMode.cs @@ -56,6 +56,9 @@ public enum VisualStylesMode : short /// Controls opt into the .NET 11 rendering changes they support. For example, support for /// depends on the control and its current state. /// + /// + /// For controls hosted through , this mode is not applied. + /// /// Net11 = 2, diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ToolStripControlHostTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ToolStripControlHostTests.cs index e982f3a6d87..d48787dd54a 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ToolStripControlHostTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ToolStripControlHostTests.cs @@ -4557,6 +4557,52 @@ public void ToolStripControlHost_SetVisibleCore_InvokeWithHandler_CallsVisibleCh Assert.Equal(2, callCount); } + [WinFormsFact] + public void ToolStripControlHost_HostedControlVisualStylesMode_Net11_IsForcedToClassic() + { + using Control control = new() + { + VisualStylesMode = VisualStylesMode.Net11 + }; + using ToolStripControlHost host = new(control); + using ToolStrip toolStrip = new(); + + toolStrip.Items.Add(host); + + Assert.Equal(VisualStylesMode.Classic, control.VisualStylesMode); + } + + [WinFormsFact] + public void ToolStripControlHost_HostedControlVisualStylesMode_SetToNet11WhileHosted_RemainsClassic() + { + using Control control = new(); + using ToolStripControlHost host = new(control); + using ToolStrip toolStrip = new(); + + toolStrip.Items.Add(host); + control.VisualStylesMode = VisualStylesMode.Net11; + + Assert.Equal(VisualStylesMode.Classic, control.VisualStylesMode); + } + + [WinFormsFact] + public void ToolStripControlHost_HostedControlVisualStylesMode_RemovingHost_RestoresRequestedMode() + { + using Control control = new() + { + VisualStylesMode = VisualStylesMode.Net11 + }; + using ToolStripControlHost host = new(control); + using ToolStrip toolStrip = new(); + + toolStrip.Items.Add(host); + Assert.Equal(VisualStylesMode.Classic, control.VisualStylesMode); + + toolStrip.Items.Remove(host); + + Assert.Equal(VisualStylesMode.Net11, control.VisualStylesMode); + } + private class SubControl : Control { public new void CreateControl() => base.CreateControl();