From 0558a09ec41af17c7dc1f9d9826b25efa8b7f0e6 Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Mon, 27 Jul 2026 17:35:07 +0800 Subject: [PATCH 1/5] Fix issue 14808: CheckBox/RadioButton: ToggleSwitch overlaps text when RightToLeft is enabled and AutoSize is false --- .../CheckBox/AnimatedToggleSwitchRenderer.cs | 59 +++++++++++++++---- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs index 42a4443bf63..94a66d79c3c 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; @@ -79,14 +79,12 @@ public override void RenderControl(Graphics graphics) ToggleSwitchMetrics metrics = ToggleSwitchMetrics.Create(Control); Size textSize = TextRenderer.MeasureText(Control.Text, Control.Font); Rectangle contentBounds = ToggleSwitchMetrics.GetContentBounds(Control); - int totalHeight = Math.Max(textSize.Height, metrics.SwitchHeight); - int contentTop = contentBounds.Top + Math.Max(0, (contentBounds.Height - totalHeight) / 2); - int textY = contentTop + ((totalHeight - textSize.Height) / 2); Rectangle switchBounds = GetSwitchBounds( Control, RtlTranslatedCheckAlign, metrics, textSize); + Rectangle textBounds = GetTextBounds(contentBounds, switchBounds, metrics, RtlTranslatedCheckAlign); graphics.Clear(Control.BackColor); @@ -97,14 +95,13 @@ public override void RenderControl(Graphics graphics) if (IsSwitchOnRight(RtlTranslatedCheckAlign)) { - int textX = Math.Max(contentBounds.Left, switchBounds.Left - metrics.TextGap - textSize.Width); RenderSwitch(graphics, switchBounds, metrics); - RenderText(graphics, new Point(textX, textY)); + RenderText(graphics, textBounds); } else { RenderSwitch(graphics, switchBounds, metrics); - RenderText(graphics, new Point(contentBounds.Left + metrics.SwitchWidth + metrics.TextGap, textY)); + RenderText(graphics, textBounds); } if (Control.Focused && ShowFocusCues) @@ -172,16 +169,58 @@ private static Rectangle GetSwitchBounds( return new Rectangle(switchX, switchY, metrics.SwitchWidth, metrics.SwitchHeight); } - private void RenderText(Graphics graphics, Point position) + internal static Rectangle GetTextBounds( + Control control, + ContentAlignment checkAlign, + ToggleSwitchMetrics metrics) { + Size textSize = TextRenderer.MeasureText(control.Text, control.Font); + Rectangle contentBounds = ToggleSwitchMetrics.GetContentBounds(control); + Rectangle switchBounds = GetSwitchBounds(control, checkAlign, metrics, textSize); + return GetTextBounds(contentBounds, switchBounds, metrics, checkAlign); + } + + private static Rectangle GetTextBounds( + Rectangle contentBounds, + Rectangle switchBounds, + ToggleSwitchMetrics metrics, + ContentAlignment checkAlign) + { + if (IsSwitchOnRight(checkAlign)) + { + int right = Math.Max(contentBounds.Left, switchBounds.Left - metrics.TextGap); + return Rectangle.FromLTRB(contentBounds.Left, contentBounds.Top, right, contentBounds.Bottom); + } + + int left = Math.Min(contentBounds.Right, switchBounds.Right + metrics.TextGap); + return Rectangle.FromLTRB(left, contentBounds.Top, contentBounds.Right, contentBounds.Bottom); + } + + private void RenderText(Graphics graphics, Rectangle textBounds) + { + if (textBounds.Width <= 0 || textBounds.Height <= 0) + { + return; + } + + TextFormatFlags flags = GetTextFormatFlags(); + TextRenderer.DrawText( graphics, Control.Text, Control.Font, - position, - GetTextColor()); + textBounds, + GetTextColor(), + flags); } + private TextFormatFlags GetTextFormatFlags() => Control switch + { + Forms.CheckBox checkBox => checkBox.CreateTextFormatFlags(), + Forms.RadioButton radioButton => radioButton.CreateTextFormatFlags(), + _ => TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl + }; + internal Color GetTextColor() => Control.Enabled ? Control.ForeColor From 4a4f5bf5c210d09953ddea2da5fdc2a43d2dcbab Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Tue, 28 Jul 2026 11:05:15 +0800 Subject: [PATCH 2/5] Fixed the issue where images were being cut. --- .../CheckBox/AnimatedToggleSwitchRenderer.cs | 21 ++++++++++++++----- .../System/Windows/Forms/CheckBoxTests.cs | 18 +++++++++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs index 94a66d79c3c..02182a26dce 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs @@ -162,9 +162,13 @@ private static Rectangle GetSwitchBounds( int totalHeight = Math.Max(textSize.Height, metrics.SwitchHeight); int contentTop = contentBounds.Top + Math.Max(0, (contentBounds.Height - totalHeight) / 2); int switchY = contentTop + ((totalHeight - metrics.SwitchHeight) / 2); - int switchX = IsSwitchOnRight(checkAlign) - ? Math.Max(contentBounds.Left, contentBounds.Right - metrics.SwitchWidth) - : contentBounds.Left; + int minimumSwitchX = contentBounds.Left; + int maximumSwitchX = Math.Max(minimumSwitchX, contentBounds.Right - metrics.SwitchWidth); + int edgeInset = Math.Max(1, (metrics.BorderThickness / 2) + 1); + int targetSwitchX = IsSwitchOnRight(checkAlign) + ? maximumSwitchX - edgeInset + : minimumSwitchX + edgeInset; + int switchX = Math.Max(minimumSwitchX, Math.Min(maximumSwitchX, targetSwitchX)); return new Rectangle(switchX, switchY, metrics.SwitchWidth, metrics.SwitchHeight); } @@ -186,13 +190,20 @@ private static Rectangle GetTextBounds( ToggleSwitchMetrics metrics, ContentAlignment checkAlign) { + int thresholdExtension = Math.Max(1, metrics.BorderThickness / 2) + 1; if (IsSwitchOnRight(checkAlign)) { - int right = Math.Max(contentBounds.Left, switchBounds.Left - metrics.TextGap); + int right = Math.Min( + contentBounds.Right, + switchBounds.Left - Math.Max(0, metrics.TextGap - thresholdExtension)); + right = Math.Max(contentBounds.Left, right); return Rectangle.FromLTRB(contentBounds.Left, contentBounds.Top, right, contentBounds.Bottom); } - int left = Math.Min(contentBounds.Right, switchBounds.Right + metrics.TextGap); + int left = Math.Max( + contentBounds.Left, + switchBounds.Right + Math.Max(0, metrics.TextGap - thresholdExtension)); + left = Math.Min(contentBounds.Right, left); return Rectangle.FromLTRB(left, contentBounds.Top, contentBounds.Right, contentBounds.Bottom); } diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs index 7a9033f3f64..43c5dcf5e21 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs @@ -773,9 +773,21 @@ public void CheckBox_ToggleSwitch_CheckAlign_PositionsSwitch( metrics); Rectangle contentBounds = Rendering.CheckBox.ToggleSwitchMetrics.GetContentBounds(box); - Assert.Equal( - switchOnRight ? contentBounds.Right : contentBounds.Left, - switchOnRight ? switchBounds.Right : switchBounds.Left); + const int EdgeTolerance = 2; + if (switchOnRight) + { + Assert.InRange( + switchBounds.Right, + contentBounds.Right - EdgeTolerance, + contentBounds.Right); + } + else + { + Assert.InRange( + switchBounds.Left, + contentBounds.Left, + contentBounds.Left + EdgeTolerance); + } } [WinFormsTheory] From bb21e4fa70b32998d3246845c7137e47774f8885 Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Tue, 28 Jul 2026 17:38:40 +0800 Subject: [PATCH 3/5] Handle feedback --- .../CheckBox/AnimatedToggleSwitchRenderer.cs | 33 +++++++++----- .../System/Windows/Forms/CheckBoxTests.cs | 44 ++++++++++++++++--- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs index 02182a26dce..058b47f1e7a 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs @@ -86,23 +86,15 @@ public override void RenderControl(Graphics graphics) textSize); Rectangle textBounds = GetTextBounds(contentBounds, switchBounds, metrics, RtlTranslatedCheckAlign); - graphics.Clear(Control.BackColor); + PaintControlBackground(graphics); if (contentBounds.Width <= 0 || contentBounds.Height <= 0) { return; } - if (IsSwitchOnRight(RtlTranslatedCheckAlign)) - { - RenderSwitch(graphics, switchBounds, metrics); - RenderText(graphics, textBounds); - } - else - { - RenderSwitch(graphics, switchBounds, metrics); - RenderText(graphics, textBounds); - } + RenderSwitch(graphics, switchBounds, metrics); + RenderText(graphics, textBounds); if (Control.Focused && ShowFocusCues) { @@ -379,6 +371,25 @@ private void EnsurePositionInitialized() _positionInitialized = true; } + private void PaintControlBackground(Graphics graphics) + { + if (Control.BackgroundImage is null && !Control.BackColor.HasTransparency()) + { + graphics.Clear(Control.BackColor); + return; + } + + Rectangle clipRectangle = Rectangle.Ceiling(graphics.ClipBounds); + clipRectangle.Intersect(Control.ClientRectangle); + if (clipRectangle.Width <= 0 || clipRectangle.Height <= 0) + { + return; + } + + using PaintEventArgs paintEventArgs = new(graphics, clipRectangle); + Control.PaintBackground(paintEventArgs, clipRectangle); + } + private static float EaseOut(float value) => 1 - ((1 - value) * (1 - value)); diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs index 43c5dcf5e21..b3fe15bc9d6 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs @@ -773,12 +773,12 @@ public void CheckBox_ToggleSwitch_CheckAlign_PositionsSwitch( metrics); Rectangle contentBounds = Rendering.CheckBox.ToggleSwitchMetrics.GetContentBounds(box); - const int EdgeTolerance = 2; + int edgeTolerance = Math.Max(1, (metrics.BorderThickness / 2) + 1); if (switchOnRight) { Assert.InRange( switchBounds.Right, - contentBounds.Right - EdgeTolerance, + contentBounds.Right - edgeTolerance, contentBounds.Right); } else @@ -786,10 +786,40 @@ public void CheckBox_ToggleSwitch_CheckAlign_PositionsSwitch( Assert.InRange( switchBounds.Left, contentBounds.Left, - contentBounds.Left + EdgeTolerance); + contentBounds.Left + edgeTolerance); } } + [WinFormsFact] + public void CheckBox_ToggleSwitch_RtlLongText_AutoSizeFalse_TextBounds_DoNotOverlapSwitch() + { + using CheckBox box = new() + { + Appearance = Appearance.ToggleSwitch, + AutoSize = false, + RightToLeft = RightToLeft.Yes, + CheckAlign = ContentAlignment.MiddleLeft, + Text = "This is a very long toggle-switch label to verify RTL clipping does not overlap the switch glyph.", + Size = new Size(160, 30) + }; + + box.VisualStylesMode = VisualStylesMode.Net11; + box.CreateControl(); + + Rendering.CheckBox.ToggleSwitchMetrics metrics = Rendering.CheckBox.ToggleSwitchMetrics.Create(box); + Rectangle switchBounds = Rendering.CheckBox.AnimatedToggleSwitchRenderer.GetSwitchBounds( + box, + box.RtlTranslatedCheckAlign, + metrics); + Rectangle textBounds = Rendering.CheckBox.AnimatedToggleSwitchRenderer.GetTextBounds( + box, + box.RtlTranslatedCheckAlign, + metrics); + Rectangle overlap = Rectangle.Intersect(switchBounds, textBounds); + + Assert.True(overlap.IsEmpty); + } + [WinFormsTheory] [InlineData(96)] [InlineData(120)] @@ -1389,10 +1419,10 @@ public void CheckBox_ProcessMnemonic_ValidCases(bool useMnemonic, char charCode, } [WinFormsTheory] - [InlineData(Appearance.Button, FlatStyle.Standard, "Test", 12, 8, 100, 20)] - [InlineData(Appearance.Normal, FlatStyle.System, "Test", 12, 8, 100, 20)] - [InlineData(Appearance.Normal, FlatStyle.Flat, "Test", 12, 8, 100, 20)] - [InlineData(Appearance.Normal, FlatStyle.Standard, "Test", 12, 8, 100, 20)] + [InlineData(Appearance.Button, FlatStyle.Standard, "Test", 12, 8, 100, 20)] + [InlineData(Appearance.Normal, FlatStyle.System, "Test", 12, 8, 100, 20)] + [InlineData(Appearance.Normal, FlatStyle.Flat, "Test", 12, 8, 100, 20)] + [InlineData(Appearance.Normal, FlatStyle.Standard, "Test", 12, 8, 100, 20)] public void CheckBox_GetPreferredSizeCore_VariousStyles_ReturnsExpected( Appearance appearance, FlatStyle flatStyle, string text, int fontSize, int padding, int width, int height) { From b30729aa1e1db40d3d97bc589e618e95c832550f Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Fri, 31 Jul 2026 11:15:40 +0800 Subject: [PATCH 4/5] Fix the test issue --- .../CheckBox/AnimatedToggleSwitchRenderer.cs | 10 ++++++++++ .../System/Windows/Forms/CheckBoxTests.cs | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs index 058b47f1e7a..c64ee45aa63 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs @@ -219,6 +219,16 @@ private void RenderText(Graphics graphics, Rectangle textBounds) private TextFormatFlags GetTextFormatFlags() => Control switch { + Forms.CheckBox { FlatStyle: FlatStyle.System } checkBox => ControlPaint.CreateTextFormatFlags( + checkBox, + checkBox.TextAlign, + checkBox.ShowToolTip, + checkBox.UseMnemonic), + Forms.RadioButton { FlatStyle: FlatStyle.System } radioButton => ControlPaint.CreateTextFormatFlags( + radioButton, + radioButton.TextAlign, + radioButton.ShowToolTip, + radioButton.UseMnemonic), Forms.CheckBox checkBox => checkBox.CreateTextFormatFlags(), Forms.RadioButton radioButton => radioButton.CreateTextFormatFlags(), _ => TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs index b3fe15bc9d6..c1439072d16 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs @@ -992,6 +992,25 @@ public void CheckBox_ToggleSwitch_ThreeStateChange_UpdatesOwnerDraw() Assert.False(box.GetStyle(ControlStyles.UserPaint)); } + [WinFormsFact] + public void CheckBox_ToggleSwitch_FlatStyleSystem_DrawToBitmap_DoesNotThrow() + { + using CheckBox box = new() + { + Appearance = Appearance.ToggleSwitch, + FlatStyle = FlatStyle.System, + VisualStylesMode = VisualStylesMode.Net11, + Text = "Toggle", + Size = new Size(120, 30) + }; + using Bitmap bitmap = new(box.Width, box.Height); + + Exception exception = Record.Exception( + () => box.DrawToBitmap(bitmap, new Rectangle(Point.Empty, box.Size))); + + Assert.Null(exception); + } + private static int CountPixels(Bitmap bitmap, Color color) { int argb = color.ToArgb(); From 93891c63d5deb68e704581b7bc63104ac4568fcd Mon Sep 17 00:00:00 2001 From: "Simon Zhao (BEYONDSOFT CONSULTING INC)" Date: Mon, 3 Aug 2026 16:03:30 +0800 Subject: [PATCH 5/5] Optimize the code --- .../CheckBox/AnimatedToggleSwitchRenderer.cs | 52 ++++++++++++++----- .../System/Windows/Forms/CheckBoxTests.cs | 27 ++++++++++ 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs index c64ee45aa63..1f123df3399 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Rendering/CheckBox/AnimatedToggleSwitchRenderer.cs @@ -77,14 +77,19 @@ public override void RenderControl(Graphics graphics) focused: Control.Focused && ShowFocusCues); ToggleSwitchMetrics metrics = ToggleSwitchMetrics.Create(Control); - Size textSize = TextRenderer.MeasureText(Control.Text, Control.Font); + TextFormatFlags textFormatFlags = GetTextFormatFlags(Control); + Size textSize = MeasureText(Control, textFormatFlags); Rectangle contentBounds = ToggleSwitchMetrics.GetContentBounds(Control); Rectangle switchBounds = GetSwitchBounds( Control, RtlTranslatedCheckAlign, metrics, textSize); - Rectangle textBounds = GetTextBounds(contentBounds, switchBounds, metrics, RtlTranslatedCheckAlign); + Rectangle textBounds = GetTextBounds( + contentBounds, + switchBounds, + metrics, + RtlTranslatedCheckAlign); PaintControlBackground(graphics); @@ -94,7 +99,7 @@ public override void RenderControl(Graphics graphics) } RenderSwitch(graphics, switchBounds, metrics); - RenderText(graphics, textBounds); + RenderText(graphics, textBounds, textFormatFlags); if (Control.Focused && ShowFocusCues) { @@ -138,11 +143,14 @@ internal static Rectangle GetSwitchBounds( Control control, ContentAlignment checkAlign, ToggleSwitchMetrics metrics) - => GetSwitchBounds( + { + TextFormatFlags textFormatFlags = GetTextFormatFlags(control); + return GetSwitchBounds( control, checkAlign, metrics, - TextRenderer.MeasureText(control.Text, control.Font)); + MeasureText(control, textFormatFlags)); + } private static Rectangle GetSwitchBounds( Control control, @@ -170,7 +178,8 @@ internal static Rectangle GetTextBounds( ContentAlignment checkAlign, ToggleSwitchMetrics metrics) { - Size textSize = TextRenderer.MeasureText(control.Text, control.Font); + TextFormatFlags textFormatFlags = GetTextFormatFlags(control); + Size textSize = MeasureText(control, textFormatFlags); Rectangle contentBounds = ToggleSwitchMetrics.GetContentBounds(control); Rectangle switchBounds = GetSwitchBounds(control, checkAlign, metrics, textSize); return GetTextBounds(contentBounds, switchBounds, metrics, checkAlign); @@ -182,42 +191,57 @@ private static Rectangle GetTextBounds( ToggleSwitchMetrics metrics, ContentAlignment checkAlign) { - int thresholdExtension = Math.Max(1, metrics.BorderThickness / 2) + 1; + // Keep a small symmetric inset between the switch track and text to avoid visual collision + // with the rounded switch border in high DPI while preserving readability in narrow widths. + int textGapInset = GetSwitchTextInset(metrics); + int minimumTextGap = Math.Max(0, metrics.TextGap - textGapInset); + if (IsSwitchOnRight(checkAlign)) { int right = Math.Min( contentBounds.Right, - switchBounds.Left - Math.Max(0, metrics.TextGap - thresholdExtension)); + switchBounds.Left - minimumTextGap); right = Math.Max(contentBounds.Left, right); return Rectangle.FromLTRB(contentBounds.Left, contentBounds.Top, right, contentBounds.Bottom); } int left = Math.Max( contentBounds.Left, - switchBounds.Right + Math.Max(0, metrics.TextGap - thresholdExtension)); + switchBounds.Right + minimumTextGap); left = Math.Min(contentBounds.Right, left); return Rectangle.FromLTRB(left, contentBounds.Top, contentBounds.Right, contentBounds.Bottom); } - private void RenderText(Graphics graphics, Rectangle textBounds) + private static int GetSwitchTextInset(ToggleSwitchMetrics metrics) + => Math.Max(1, (metrics.BorderThickness / 2) + 1); + + private static Size MeasureText(Control control, TextFormatFlags textFormatFlags) + => TextRenderer.MeasureText( + text: control.Text, + font: control.Font, + proposedSize: new Size(int.MaxValue, int.MaxValue), + flags: textFormatFlags); + + private void RenderText( + Graphics graphics, + Rectangle textBounds, + TextFormatFlags textFormatFlags) { if (textBounds.Width <= 0 || textBounds.Height <= 0) { return; } - TextFormatFlags flags = GetTextFormatFlags(); - TextRenderer.DrawText( graphics, Control.Text, Control.Font, textBounds, GetTextColor(), - flags); + textFormatFlags); } - private TextFormatFlags GetTextFormatFlags() => Control switch + private static TextFormatFlags GetTextFormatFlags(Control control) => control switch { Forms.CheckBox { FlatStyle: FlatStyle.System } checkBox => ControlPaint.CreateTextFormatFlags( checkBox, diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs index c1439072d16..04d30f6fc95 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/CheckBoxTests.cs @@ -820,6 +820,33 @@ public void CheckBox_ToggleSwitch_RtlLongText_AutoSizeFalse_TextBounds_DoNotOver Assert.True(overlap.IsEmpty); } + [WinFormsFact] + public void CheckBox_ToggleSwitch_NarrowWidth_TextBoundsCanCollapseWithoutThrowing() + { + using CheckBox box = new() + { + Appearance = Appearance.ToggleSwitch, + AutoSize = false, + Text = "Narrow control text", + Size = new Size(8, 30), + VisualStylesMode = VisualStylesMode.Net11 + }; + using Bitmap bitmap = new(box.Width, box.Height); + + Exception exception = Record.Exception( + () => box.DrawToBitmap(bitmap, new Rectangle(Point.Empty, box.Size))); + + Assert.Null(exception); + + Rendering.CheckBox.ToggleSwitchMetrics metrics = Rendering.CheckBox.ToggleSwitchMetrics.Create(box); + Rectangle textBounds = Rendering.CheckBox.AnimatedToggleSwitchRenderer.GetTextBounds( + box, + box.RtlTranslatedCheckAlign, + metrics); + + Assert.InRange(textBounds.Width, 0, 1); + } + [WinFormsTheory] [InlineData(96)] [InlineData(120)]