Skip to content

Dark Mode issues Fixes #13474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open

Dark Mode issues Fixes #13474

wants to merge 26 commits into from

Conversation

memoarfaa
Copy link

@memoarfaa memoarfaa commented May 17, 2025

Fixes #12027
Fixes #12992
Fixes #12991
Fixes #12582
Fixes #11941
Fixes #11932
Fixes #13636

Proposed changes

Dark Mode Specific Fixes and Improvements

Core and System Colors

  • Improved the management of GDI brushes to avoid memory leaks when using alternative color sets (such as Dark Mode). Solid brushes are now properly created and cleaned up based on theme changes.
  • Enhanced the handling of system color brushes to ensure accurate color application and resource cleanup when switching between color modes.

Application Theme Propagation

  • Improved theme change propagation: When the color mode changes (e.g., to Dark Mode), all windows in the application are notified to update their theme, ensuring consistent appearance across the app.
  • Updated the recursive message sending for theme changes to ensure both WM_SYSCOLORCHANGE and WM_THEMECHANGED messages are dispatched correctly.

Control Rendering & Theming

  • Optimized background brush selection for controls to reduce redundant caching and ensure correct brush usage in Dark Mode.
  • Introduced logic to update theming for specific controls (ProgressBar, ComboBox, ListView, and others) to apply the correct Dark Mode themes.
  • Updated OnSystemColorsChanged to trigger theming updates for child controls as well.

Window and Non-Client Area

  • Added handling for the WM_DWMNCRENDERINGCHANGED message to update non-client (title bar, borders) rendering policy in response to system theme changes.
  • Enhanced Form's message handling to properly update dark mode attributes, redraw the non-client area, and ensure correct theme application for MDI containers and menu bars in Dark Mode.
  • Improved logic for redrawing menu bars and handling mouse interactions with menu items under Dark Mode.

PropertyGrid and TreeView Controls

  • Updated PropertyGrid's glyph theming to use Dark Mode-specific VisualStyleElements when Dark Mode is active.
  • Enhanced TreeView to properly close and refresh theme data when the system theme changes to Dark Mode, ensuring consistent appearance.

ToolStrips

  • Improved ToolStrip renderer cache invalidation when color preferences change, ensuring toolbars update their colors promptly when switching themes.

Form Properties and Documentation

  • Extended documentation for Form border and caption color properties to clarify behavior when set to transparent or empty.
  • Improved internal logic for setting and resetting window attribute colors based on current theme.

Integration Test Application

  • Enhanced the test application's MainForm to provide a UI for switching between System, Classic, and Dark color modes, allowing for easier manual validation of theme changes.
  • Improved focus handling and layout updates to reflect the selected color mode immediately.

Customer Impact

  • End users experience a more visually consistent and reliable dark mode.
  • Improved appearance and usability of controls in dark mode, resolving previously reported rendering bugs.
  • Developers can more easily test and validate color mode switching.

Regression?

  • No

Risk

  • Low: The changes focus on visual improvements and resource management, with manual and integration test coverage.

Test methodology

  • Manual testing across affected controls and color modes, including dark mode and high-DPI environments.
  • Verified correct rendering for Button, ComboBox, Toolbar, Header, Status, TreeView, PropertyGrid, menus, and MDI containers.
  • Ran existing integration tests and validated color mode switching in the test app.

Accessibility testing

Test environment(s)

  • Windows 11, Latest .NET 10 SDK build: 10.0.100-preview.6.25311.107
  • UI scaling tested at 100% and higher settings.

@memoarfaa memoarfaa requested a review from a team as a code owner May 17, 2025 20:53
@github-actions github-actions bot added the area-DarkMode Issues relating to Dark Mode feature label May 17, 2025
Copy link

codecov bot commented May 18, 2025

Codecov Report

Attention: Patch coverage is 18.47826% with 225 lines in your changes missing coverage. Please review.

Project coverage is 76.57709%. Comparing base (b90e189) to head (faeff85).

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main      #13474         +/-   ##
===================================================
- Coverage   76.60173%   76.57709%   -0.02465%     
===================================================
  Files           3253        3253                 
  Lines         640996      641244        +248     
  Branches       47439       47483         +44     
===================================================
+ Hits          491014      491046         +32     
- Misses        146330      146539        +209     
- Partials        3652        3659          +7     
Flag Coverage Δ
Debug 76.57709% <18.47826%> (-0.02465%) ⬇️
integration 18.97291% <11.59420%> (-0.01501%) ⬇️
production 51.02155% <18.47826%> (-0.03286%) ⬇️
test 97.41175% <ø> (ø)
unit 48.40448% <15.21739%> (-0.03268%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@KlausLoeffelmann
Copy link
Member

Hey @memoarfaa,

thanks for this PR, but let's try to coordinate the efforts here, so we're not doing redundant work.
Can you explain, which parts of the your PR is addressing which Issues, and point out the background a bit?

We'll be addressing for Preview 5 (maybe early 6) the PRs which I did, since they had been planned and championed. We only have Monday 19th to complete testing, reviews and merge them, so the Preview 5 ship for any pivoting in approaches has sailed.

For Preview 6, I'd love to re-discuss approaches, though, so, let's keep the discussion rolling for improvements for the Preview 6 time frame!

PS:
If you have a good, feasible idea or approach, which we could take on (really!) short notice for the background-coloring of a read-only TextBox or RTF TextBox in DarkMode, without changing the default color (which would be too invasive), that would be really cool!!

@memoarfaa
Copy link
Author

memoarfaa commented May 19, 2025

Hey @memoarfaa,

Hey @KlausLoeffelmann

thanks for this PR, but let's try to coordinate the efforts here, so we're not doing redundant work. Can you explain, which parts of the your PR is addressing which Issues, and point out the background a bit?

Ok I will do

We'll be addressing for Preview 5 (maybe early 6) the PRs which I did, since they had been planned and championed. We only have Monday 19th to complete testing, reviews and merge them, so the Preview 5 ship for any pivoting in approaches has sailed.

I understand that for Preview 5, only the already planned/championed PRs can be considered, and my changes won’t be merged at this stage.

For Preview 6, I'd love to re-discuss approaches, though, so, let's keep the discussion rolling for improvements for the Preview 6 time frame!

For Preview 6, I’m happy to continue iterating on these improvements and would appreciate any feedback or direction from the team on priorities or preferred approaches.

PS: If you have a good, feasible idea or approach, which we could take on (really!) short notice for the background-coloring of a read-only TextBox or RTF TextBox in DarkMode, without changing the default color (which would be too invasive), that would be really cool!!

About Read-Only TextBox Background Coloring in Dark Mode

I don't understand what you mean by

"without changing the default color"

If you mean the Win32 default theme Color the answer is no because it handled by WM_CTLCOLOR XXXX
if you mean the WinForms repo defaults BackColor and ForColor I'm using the same approach in Win32 WM_CTLCOLOR XXXX
explanation,
in TextBoxBase class

internal override HBRUSH InitializeDCForWmCtlColor(HDC dc, MessageId msg)
   {
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
       bool isReadOnly = (PInvokeCore.GetWindowLong(this, WINDOW_LONG_PTR_INDEX.GWL_STYLE) & PInvoke.ES_READONLY) != 0;
       if (Application.IsDarkModeEnabled && isReadOnly)
       {
           switch (msg)
           {
               // In dark mode, a disabled edit control will paint the background and forground with light colors
               case PInvokeCore.WM_CTLCOLOREDIT:
                   PInvokeCore.SetBkColor(dc, 0x1A1A1A);
                   PInvokeCore.SetTextColor(dc, 0xffffff);
                   return PInvokeCore.CreateSolidBrush(0x1A1A1A);
               case PInvokeCore.WM_CTLCOLORSTATIC:
                   PInvokeCore.SetBkMode(dc, BACKGROUND_MODE.TRANSPARENT);
                   PInvokeCore.SetTextColor(dc, 0x6A6A6A);
                   return PInvokeCore.CreateSolidBrush(0x232323);
               default:
                   return base.InitializeDCForWmCtlColor(dc, msg);
           }
       }

#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
    else
       {
           if (msg == PInvokeCore.WM_CTLCOLORSTATIC && !ShouldSerializeBackColor())
           {
               // Let the Win32 Edit control handle background colors itself.
               // This is necessary because a disabled edit control will display a different
               // BackColor than when enabled.
               return default;

           }
           else
           {
               return base.InitializeDCForWmCtlColor(dc, msg);
           }
       }
   }

in RichTextBox Class

    private bool InternalSetForeColor(Color value)
    {

        CHARFORMAT2W cf = GetCharFormat(false);
        if ((cf.dwMask & CFM_MASK.CFM_COLOR) != 0
            && ColorTranslator.ToWin32(value) == cf.crTextColor)
        {
            return true;
        }

        cf.dwMask = CFM_MASK.CFM_COLOR;
        cf.dwEffects = 0;
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
        cf.crTextColor = Application.IsDarkModeEnabled && ReadOnly
            ? 0x6A6A6A
            : ColorTranslator.ToWin32(value);
#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
        return SetCharFormat(PInvoke.SCF_ALL, cf);
    }

Recording.2025-05-19.095641.mp4

@memoarfaa
Copy link
Author

@JeremyKuhne
@merriemcgaw
this done now

@KlausLoeffelmann Do you have any questions about the code background or any suggestions for changes?

Hey @memoarfaa,

thanks for this PR, but let's try to coordinate the efforts here, so we're not doing redundant work. Can you explain, which parts of the your PR is addressing which Issues, and point out the background a bit?

@memoarfaa
Copy link
Author

@Olina-Zhang
If you have some time, can you confirm that all the issues in these Pull request have been resolved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment