From 240db422d9944993d8b4110258831dbaea598aaa Mon Sep 17 00:00:00 2001 From: Apoorv Darshan Date: Tue, 17 Feb 2026 13:17:18 +0530 Subject: [PATCH] Fix dark mode invisible text for CheckBox/RadioButton with FlatStyle.System When dark mode is enabled, CheckBox and RadioButton controls with FlatStyle.System display invisible text because InitializeDCForWmCtlColor sets the text color to SystemColors.ControlText (dark) against the dark background applied by SetWindowTheme. Override InitializeDCForWmCtlColor in ButtonBase to return default when dark mode is active and FlatStyle.System is used, letting the dark theme handle text and background colors correctly. This follows the same pattern used by ScrollBar. Fixes dotnet/winforms#11950 --- .../Forms/Controls/Buttons/ButtonBase.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/Buttons/ButtonBase.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/Buttons/ButtonBase.cs index 26c3292e175..ffe5edee645 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/Buttons/ButtonBase.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/Buttons/ButtonBase.cs @@ -1348,6 +1348,23 @@ private void ResetUseVisualStyleBackColor() private bool ShouldSerializeUseVisualStyleBackColor() => _isEnableVisualStyleBackgroundSet; + internal override HBRUSH InitializeDCForWmCtlColor(HDC dc, MessageId msg) + { + // In dark mode with FlatStyle.System, the control is rendered by the system with a dark + // theme applied via SetWindowTheme. The default SystemColors (ControlText, Control) don't + // reflect the dark theme, causing dark text on a dark background. Return default to let + // the dark theme handle text and background colors correctly. + if (FlatStyle == FlatStyle.System + && Application.IsDarkModeEnabled + && !ShouldSerializeForeColor() + && !ShouldSerializeBackColor()) + { + return default; + } + + return base.InitializeDCForWmCtlColor(dc, msg); + } + protected override void WndProc(ref Message m) { switch (m.MsgInternal)