diff --git a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt
index 3980fbc2d4e..8bd02677e21 100644
--- a/src/System.Windows.Forms.Primitives/src/NativeMethods.txt
+++ b/src/System.Windows.Forms.Primitives/src/NativeMethods.txt
@@ -221,6 +221,7 @@ GetUpdateRgn
GetUserObjectInformation
GetViewportExtEx
GetWindow
+GetWindowTheme
GetWindowDpiAwarenessContext
GetWindowPlacement
GetWorldTransform
diff --git a/src/System.Windows.Forms/System/Windows/Forms/Application.cs b/src/System.Windows.Forms/System/Windows/Forms/Application.cs
index abb5ee2fb3e..f6621d51b44 100644
--- a/src/System.Windows.Forms/System/Windows/Forms/Application.cs
+++ b/src/System.Windows.Forms/System/Windows/Forms/Application.cs
@@ -313,6 +313,7 @@ public static void SetColorMode(SystemColorMode systemColorMode)
{
SystemColors.UseAlternativeColorSet = darkModeEnabled;
NotifySystemEventsOfColorChange();
+ PInvokeCore.EnumWindows(SendThemeChanged);
}
}
diff --git a/src/System.Windows.Forms/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/System/Windows/Forms/Control.cs
index 96cb4f0efcf..ea28b2f5139 100644
--- a/src/System.Windows.Forms/System/Windows/Forms/Control.cs
+++ b/src/System.Windows.Forms/System/Windows/Forms/Control.cs
@@ -10306,7 +10306,8 @@ protected virtual void SetVisibleCore(bool value)
{
// We shouldn't mess with the color mode if users haven't specifically set it.
// https://github.com/dotnet/winforms/issues/12014
- if (value && Application.ColorModeSet)
+ // I Don't think we should be doing this for Forms here , but it is the same as the old code but execute Form Control.
+ if (value && Application.ColorModeSet && this is not Form)
{
PrepareDarkMode(HWND, Application.IsDarkModeEnabled);
}
@@ -10314,7 +10315,7 @@ protected virtual void SetVisibleCore(bool value)
PInvoke.ShowWindow(HWND, value ? ShowParams : SHOW_WINDOW_CMD.SW_HIDE);
}
}
-#pragma warning restore WFO5001
+#pragma warning restore WFO5001w
else if (IsHandleCreated || (value && _parent?.Created == true))
{
// We want to mark the control as visible so that CreateControl
@@ -12481,6 +12482,24 @@ protected virtual void WndProc(ref Message m)
case PInvokeCore.WM_SETTINGCHANGE:
if (GetExtendedState(ExtendedStates.InterestedInUserPreferenceChanged) && GetTopLevel())
{
+ // need Handle immediately drawing of Scrollbars.
+#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.
+ Application.SetColorMode(Application.ColorMode);
+ const string DarkModeThemeIdentifier = $"{DarkModeIdentifier}_{ExplorerThemeIdentifier}";
+ PInvoke.SetWindowTheme(m.HWND,
+ Application.IsDarkModeEnabled
+ ? DarkModeThemeIdentifier
+ : default,
+ null);
+ PInvoke.RedrawWindow(
+ m.HWND,
+ lprcUpdate: (RECT*)null,
+ HRGN.Null,
+ REDRAW_WINDOW_FLAGS.RDW_INVALIDATE
+ | REDRAW_WINDOW_FLAGS.RDW_FRAME
+ | REDRAW_WINDOW_FLAGS.RDW_ERASE
+ | REDRAW_WINDOW_FLAGS.RDW_ALLCHILDREN);
+#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.
SYSTEM_PARAMETERS_INFO_ACTION action = (SYSTEM_PARAMETERS_INFO_ACTION)(uint)m.WParamInternal;
// Left here for debugging purposes.
diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs
index 64203a7eb2b..aaba17a28ff 100644
--- a/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs
+++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs
@@ -3398,6 +3398,16 @@ protected override unsafe void WndProc(ref Message m)
case PInvokeCore.WM_SYSCOLORCHANGE:
PInvokeCore.SendMessage(this, PInvoke.TVM_SETINDENT, (WPARAM)Indent);
base.WndProc(ref m);
+ break;
+ case PInvokeCore.WM_THEMECHANGED:
+#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.
+ if (Application.IsDarkModeEnabled)
+ {
+ HTHEME theme = PInvoke.GetWindowTheme(m.HWND);
+ PInvoke.CloseThemeData(theme);
+ m.ResultInternal = (LRESULT)0;
+ }
+
break;
case PInvokeCore.WM_SETFOCUS:
// If we get focus through the LButtonDown .. we might have done the validation...
diff --git a/src/System.Windows.Forms/System/Windows/Forms/Form.cs b/src/System.Windows.Forms/System/Windows/Forms/Form.cs
index f5da26c3ea1..79471b7b58a 100644
--- a/src/System.Windows.Forms/System/Windows/Forms/Form.cs
+++ b/src/System.Windows.Forms/System/Windows/Forms/Form.cs
@@ -2265,6 +2265,9 @@ private unsafe void SetFormCornerPreferenceInternal(FormCornerPreference cornerP
/// those changes, as the Win32 API does not provide a mechanism to retrieve the current title
/// bar color.
///
+ ///
+ /// Note: Setting to suppresses the drawing of the window border, allowing the form to have rounded corners without a visible border. Setting to resets it to the system default color.
+ ///
///
/// The property only reflects the value that was previously set using this property. The
/// event is raised accordingly when the value is
@@ -2327,6 +2330,9 @@ protected virtual void OnFormBorderColorChanged(EventArgs e)
/// those changes, as the Win32 API does not provide a mechanism to retrieve the current title
/// bar color.
///
+ ///
+ /// Note: Setting to resets it to the system default color.
+ ///
///
/// The property only reflects the value that was previously set using this property. The
/// event is raised accordingly when the value is
@@ -2395,6 +2401,9 @@ protected virtual void OnFormCaptionBackColorChanged(EventArgs e)
/// event is raised accordingly when the value is
/// changed, which allows the property to be participating in binding scenarios.
///
+ ///
+ /// Note: Setting to resets it to the system default color.
+ ///
///
[SRCategory(nameof(SR.CatWindowStyle))]
[SRDescription(nameof(SR.FormCaptionTextColorDescr))]
@@ -2453,7 +2462,11 @@ private unsafe Color GetFormAttributeColorInternal(DWMWINDOWATTRIBUTE dmwWindowA
private unsafe void SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE dmwWindowAttribute, Color color)
{
- COLORREF colorRef = color;
+ COLORREF colorRef = color.IsEmpty ? (COLORREF)(Color.White.ToArgb()) : (COLORREF)color;
+ if (color == Color.Transparent && dmwWindowAttribute == DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR)
+ {
+ colorRef = (COLORREF)(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFE).ToArgb());
+ }
PInvoke.DwmSetWindowAttribute(
HWND,
@@ -4509,6 +4522,28 @@ public event DpiChangedEventHandler? DpiChanged
remove => Events.RemoveHandler(s_dpiChangedEvent, value);
}
+ ///
+ /// Handles the WM_THEMECHANGED message for the form. Updates the window's immersive dark mode attribute
+ /// if the application's color mode is set, ensuring the form reflects the current system theme (light or dark).
+ ///
+ /// The Windows message containing theme change information.
+ private unsafe void WmThemeChanged(ref Message m)
+ {
+ base.WndProc(ref m);
+ if (Application.ColorModeSet && GetTopLevel())
+ {
+#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 value = Application.IsDarkModeEnabled;
+#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.
+
+ PInvoke.DwmSetWindowAttribute(
+ m.HWND,
+ DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
+ &value,
+ (uint)sizeof(BOOL)).AssertSuccess();
+ }
+ }
+
///
/// Handles the WM_DPICHANGED message
///
@@ -6535,11 +6570,34 @@ private void WmExitSizeMove()
///
/// WM_CREATE handler
///
- private void WmCreate(ref Message m)
+ private unsafe void WmCreate(ref Message m)
{
base.WndProc(ref m);
PInvoke.GetStartupInfo(out STARTUPINFOW si);
+#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.
+ if (TopLevel && IsHandleCreated)
+ {
+ FormCornerPreference formCornerPreference = Properties.GetValueOrDefault(s_propFormCornerPreference, FormCornerPreference.Default);
+ SetFormCornerPreferenceInternal(formCornerPreference);
+ Color colorValue = Properties.GetValueOrDefault(s_propFormCaptionTextColor, Color.Empty);
+ SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_TEXT_COLOR, colorValue);
+
+ colorValue = Properties.GetValueOrDefault(s_propFormCaptionBackColor, Color.Empty);
+ SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, colorValue);
+
+ colorValue = Properties.GetValueOrDefault(s_propFormBorderColor, Color.Empty);
+ SetFormAttributeColorInternal(DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, colorValue);
+ }
+
+ // Set the theme for the form. This is needed to set the dark mode theme
+ if (Application.IsDarkModeEnabled && Application.ColorModeSet)
+ {
+ BOOL value = true;
+ PInvoke.DwmSetWindowAttribute(HWND, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(int));
+ }
+
+#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to chang
// If we've been created from explorer, it may
// force us to show up normal. Force our current window state to
// the specified state, unless it's _specified_ max or min
@@ -7116,6 +7174,9 @@ protected override void WndProc(ref Message m)
case PInvokeCore.WM_DPICHANGED:
WmDpiChanged(ref m);
break;
+ case PInvokeCore.WM_THEMECHANGED:
+ WmThemeChanged(ref m);
+ break;
default:
base.WndProc(ref m);
break;