From 2b3545ce7dbb925947480638256de3dc8f210749 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 25 Aug 2024 17:57:17 +0300 Subject: [PATCH 1/8] Add dark mode theme to tab control without tab appearance property support. --- .../src/System/Windows/Forms/Control.cs | 2 +- .../Forms/Controls/TabControl/TabControl.cs | 18 ++++++++++++++++++ .../Forms/Controls/TabControl/TabRenderer.cs | 10 ++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index eea81eb8fbc..3e63bc0b709 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -163,7 +163,7 @@ public unsafe partial class Control : internal const string ExplorerThemeIdentifier = "Explorer"; internal const string ItemsViewThemeIdentifier = "ItemsView"; internal const string ComboBoxButtonThemeIdentifier = "CFD"; - + internal const string TabThemeIdentifier = "FileExplorerBannerContainer"; private const short PaintLayerBackground = 1; private const short PaintLayerForeground = 2; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs index fdacf2dc94d..6e10bc83c48 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs @@ -1259,6 +1259,13 @@ protected override void OnHandleCreated(EventArgs e) 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE); } + +#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) + { + PInvoke.SendMessage(tooltipHwnd, PInvoke.TTM_SETWINDOWTHEME, default, "DarkMode_Explorer"); + } +#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. } // Add the pages @@ -1288,6 +1295,17 @@ protected override void OnHandleCreated(EventArgs e) } UpdateTabSelection(false); + // TabControl didn't have Tab Appearance in Dark mode theme to support Dark Mode Tab Appearance we need to draw The buttons in paint event. + +#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 && GetStyle(ControlStyles.ApplyThemingImplicitly)) + { + _ = PInvoke.SetWindowTheme( + hwnd: HWND, + pszSubAppName: null, + pszSubIdList: $"{DarkModeIdentifier}::{TabThemeIdentifier}"); + } +#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. } protected override void OnHandleDestroyed(EventArgs e) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs index 866aa65da29..65db6771d49 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs @@ -3,7 +3,6 @@ using System.Drawing; using System.Windows.Forms.VisualStyles; - namespace System.Windows.Forms; /// @@ -144,7 +143,14 @@ public static void DrawTabPage(Graphics g, Rectangle bounds) internal static void DrawTabPage(IDeviceContext deviceContext, Rectangle bounds) { - InitializeRenderer(VisualStyleElement.Tab.Pane.Normal, 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. + VisualStyleElement darkTabPaneElement = VisualStyleElement.CreateElement("DarkMode::ExplorerNavPane", 0, 0); + VisualStyleElement lightTabPaneElement = VisualStyleElement.Tab.Pane.Normal; + VisualStyleElement tabPaneElement = Application.IsDarkModeEnabled + ? darkTabPaneElement + : lightTabPaneElement; + InitializeRenderer(tabPaneElement, 0); +#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. t_visualStyleRenderer.DrawBackground(deviceContext, bounds); } From 7e309f44086c59294cca7970e33d79eaef6ef408 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 25 Aug 2024 18:32:57 +0300 Subject: [PATCH 2/8] Add Dark Mode theme to rows/columns and ColumnHeader/RowHeader in the DataGridView --- .../Controls/ComboBox/ComboBoxRenderer.cs | 6 ++++- .../DataGridView/DataGridViewButtonCell.cs | 7 ++++- .../DataGridView/DataGridViewCheckBoxCell.cs | 8 +++++- ...ll.DataGridViewColumnHeaderCellRenderer.cs | 7 ++++- .../DataGridViewColumnHeaderCell.cs | 6 ++++- ...oxCell.DataGridViewComboBoxCellRenderer.cs | 27 ++++++++++++++++--- .../DataGridView/DataGridViewRowHeaderCell.cs | 6 ++++- .../DataGridViewTopLeftHeaderCell.cs | 6 ++++- .../Forms/Controls/TabControl/TabRenderer.cs | 2 ++ 9 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs index af1b1c9ff11..3508e526c5b 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs @@ -14,7 +14,11 @@ public static class ComboBoxRenderer // Make this per-thread, so that different threads can safely use these methods. [ThreadStatic] private static VisualStyleRenderer? t_visualStyleRenderer; - private static readonly VisualStyleElement s_comboBoxElement = VisualStyleElement.ComboBox.DropDownButton.Normal; +#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. + private static readonly VisualStyleElement s_comboBoxElement = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 1, 1) + : VisualStyleElement.ComboBox.DropDownButton.Normal; +#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. private static readonly VisualStyleElement s_textBoxElement = VisualStyleElement.TextBox.TextEdit.Normal; /// diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs index d1d5af1608c..0b642422bde 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs @@ -17,7 +17,12 @@ public partial class DataGridViewButtonCell : DataGridViewCell private static readonly int s_propButtonCellFlatStyle = PropertyStore.CreateKey(); private static readonly int s_propButtonCellState = PropertyStore.CreateKey(); private static readonly int s_propButtonCellUseColumnTextForButtonValue = PropertyStore.CreateKey(); - private static readonly VisualStyleElement s_buttonElement = VisualStyleElement.Button.PushButton.Normal; +#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. + private static readonly VisualStyleElement s_darkButtonElement = VisualStyleElement.CreateElement("DarkMode_Explorer::BUTTON", 1, 1); + private static readonly VisualStyleElement s_lightButtonElement = VisualStyleElement.Button.PushButton.Normal; + private static readonly VisualStyleElement s_buttonElement = Application.IsDarkModeEnabled ? s_darkButtonElement : s_lightButtonElement; +#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. + private const byte DATAGRIDVIEWBUTTONCELL_themeMargin = 100; // Used to calculate the margins required for theming rendering private const byte DATAGRIDVIEWBUTTONCELL_horizontalTextMargin = 2; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs index 1148a0e5f11..79ca2ba0031 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs @@ -20,7 +20,13 @@ public partial class DataGridViewCheckBoxCell : DataGridViewCell, IDataGridViewE private const DataGridViewContentAlignment AnyBottom = DataGridViewContentAlignment.BottomRight | DataGridViewContentAlignment.BottomCenter | DataGridViewContentAlignment.BottomLeft; private const DataGridViewContentAlignment AnyMiddle = DataGridViewContentAlignment.MiddleRight | DataGridViewContentAlignment.MiddleCenter | DataGridViewContentAlignment.MiddleLeft; - private static readonly VisualStyleElement s_checkBoxElement = VisualStyleElement.Button.CheckBox.UncheckedNormal; +#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. + private static readonly VisualStyleElement s_darkCheckBoxElement = VisualStyleElement.CreateElement("DarkMode_Explorer::BUTTON", 3, 1); + private static readonly VisualStyleElement s_lightCheckBoxElement = VisualStyleElement.Button.CheckBox.UncheckedNormal; + private static readonly VisualStyleElement s_checkBoxElement = Application.IsDarkModeEnabled ? s_darkCheckBoxElement : s_lightCheckBoxElement; +#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. + + private static readonly int s_propButtonCellState = PropertyStore.CreateKey(); private static readonly int s_propTrueValue = PropertyStore.CreateKey(); private static readonly int s_propFalseValue = PropertyStore.CreateKey(); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs index 47a8fd77cac..e1ba42a6242 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs @@ -16,7 +16,12 @@ public static VisualStyleRenderer VisualStyleRenderer { get { - s_visualStyleRenderer ??= new VisualStyleRenderer(s_headerElement); +#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. + s_visualStyleRenderer ??= new VisualStyleRenderer(Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + : VisualStyleElement.Header.Item.Normal); +#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 s_visualStyleRenderer; } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs index 2b62f13986f..28d895060ea 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs @@ -11,7 +11,11 @@ namespace System.Windows.Forms; public partial class DataGridViewColumnHeaderCell : DataGridViewHeaderCell { - private static readonly VisualStyleElement s_headerElement = VisualStyleElement.Header.Item.Normal; +#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. + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + : VisualStyleElement.Header.Item.Normal; +#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. private const byte SortGlyphSeparatorWidth = 2; // additional 2 pixels between caption and glyph private const byte SortGlyphHorizontalMargin = 4; // 4 pixels on left & right of glyph diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs index 7c5cf83af53..2cf292d6cb4 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs @@ -12,10 +12,29 @@ private static class DataGridViewComboBoxCellRenderer { [ThreadStatic] private static VisualStyleRenderer? t_visualStyleRenderer; - private static readonly VisualStyleElement s_comboBoxBorder = VisualStyleElement.ComboBox.Border.Normal; - private static readonly VisualStyleElement s_comboBoxDropDownButtonRight = VisualStyleElement.ComboBox.DropDownButtonRight.Normal; - private static readonly VisualStyleElement s_comboBoxDropDownButtonLeft = VisualStyleElement.ComboBox.DropDownButtonLeft.Normal; - private static readonly VisualStyleElement s_comboBoxReadOnlyButton = VisualStyleElement.ComboBox.ReadOnlyButton.Normal; +#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. + private static readonly VisualStyleElement s_comboBoxBorder = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 4, 1) + : VisualStyleElement.ComboBox.Border.Normal; +#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. + +#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. + private static readonly VisualStyleElement s_comboBoxDropDownButtonRight = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 6, 1) + : VisualStyleElement.ComboBox.DropDownButtonRight.Normal; +#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. + +#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. + private static readonly VisualStyleElement s_comboBoxDropDownButtonLeft = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 7, 1) : + VisualStyleElement.ComboBox.DropDownButtonLeft.Normal; +#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. + +#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. + private static readonly VisualStyleElement s_comboBoxReadOnlyButton = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 5, 1) + : VisualStyleElement.ComboBox.ReadOnlyButton.Normal; +#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. public static VisualStyleRenderer VisualStyleRenderer { diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs index 0cb86c1a563..15ef40f698f 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs @@ -11,7 +11,11 @@ namespace System.Windows.Forms; public partial class DataGridViewRowHeaderCell : DataGridViewHeaderCell { - private static readonly VisualStyleElement s_headerElement = VisualStyleElement.Header.Item.Normal; +#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. + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + : VisualStyleElement.Header.Item.Normal; +#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. private static Bitmap? s_rightArrowBmp; private static Bitmap? s_leftArrowBmp; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs index fd144424d4d..1711106de02 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs @@ -8,7 +8,11 @@ namespace System.Windows.Forms; public partial class DataGridViewTopLeftHeaderCell : DataGridViewColumnHeaderCell { - private static readonly VisualStyleElement s_headerElement = VisualStyleElement.Header.Item.Normal; +#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. + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? + VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + : VisualStyleElement.Header.Item.Normal; +#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. private const byte DATAGRIDVIEWTOPLEFTHEADERCELL_horizontalTextMarginLeft = 1; private const byte DATAGRIDVIEWTOPLEFTHEADERCELL_horizontalTextMarginRight = 2; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs index 65db6771d49..17bcb8a3b35 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs @@ -144,6 +144,8 @@ public static void DrawTabPage(Graphics g, Rectangle bounds) internal static void DrawTabPage(IDeviceContext deviceContext, Rectangle bounds) { #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. + // Using DarkMode Theme Subclass. + // see https://learn.microsoft.com/en-us/windows/win32/controls/theme-subclasses. VisualStyleElement darkTabPaneElement = VisualStyleElement.CreateElement("DarkMode::ExplorerNavPane", 0, 0); VisualStyleElement lightTabPaneElement = VisualStyleElement.Tab.Pane.Normal; VisualStyleElement tabPaneElement = Application.IsDarkModeEnabled From e96baf545e9c2ad8a1dd0080f41970ff5c210a83 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 25 Aug 2024 19:18:38 +0300 Subject: [PATCH 3/8] Remove weak dependency on Windows Registry Key and add IsDarkModeSupported Windows Registry Key may be deleted and never restored and may be exist and there is no dark mode subclass in aero.msstyles --- .../src/PublicAPI.Shipped.txt | 1 + .../src/System/Windows/Forms/Application.cs | 20 +++----------- .../Forms/VisualStyles/VisualStyleRenderer.cs | 27 +++++++++++++++++++ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/System.Windows.Forms/src/PublicAPI.Shipped.txt b/src/System.Windows.Forms/src/PublicAPI.Shipped.txt index 3f768c490c2..89d81e41b4a 100644 --- a/src/System.Windows.Forms/src/PublicAPI.Shipped.txt +++ b/src/System.Windows.Forms/src/PublicAPI.Shipped.txt @@ -3320,6 +3320,7 @@ static System.Windows.Forms.VisualStyles.VisualStyleInformation.Url.get -> strin static System.Windows.Forms.VisualStyles.VisualStyleInformation.Version.get -> string! static System.Windows.Forms.VisualStyles.VisualStyleRenderer.IsElementDefined(System.Windows.Forms.VisualStyles.VisualStyleElement! element) -> bool static System.Windows.Forms.VisualStyles.VisualStyleRenderer.IsSupported.get -> bool +static System.Windows.Forms.VisualStyles.VisualStyleRenderer.IsDarkModeSupported.get -> bool static System.Windows.Forms.WindowsFormsSynchronizationContext.AutoInstall.get -> bool static System.Windows.Forms.WindowsFormsSynchronizationContext.AutoInstall.set -> void static System.Windows.Forms.WindowsFormsSynchronizationContext.Uninstall() -> void diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs index 77285629a6b..b4893177962 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Application.cs @@ -48,8 +48,6 @@ public sealed partial class Application private static SystemColorMode? s_colorMode; #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. - private const string DarkModeKeyPath = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; - private const string DarkModeKey = "AppsUseLightTheme"; private const int SystemDarkModeDisabled = 1; /// @@ -379,21 +377,9 @@ private static int GetSystemColorModeInternal() return SystemDarkModeDisabled; } - int systemColorMode = SystemDarkModeDisabled; - - try - { - // 0 for dark mode and |1| for light mode. - systemColorMode = Math.Abs((Registry.GetValue( - keyName: DarkModeKeyPath, - valueName: DarkModeKey, - defaultValue: SystemDarkModeDisabled) as int?) ?? systemColorMode); - } - catch (Exception ex) when (!ex.IsCriticalException()) - { - } - - return systemColorMode; +#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. + return VisualStyleRenderer.IsDarkModeSupported ? 0 : 1; +#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. } private static bool IsSystemDarkModeAvailable => diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs index e4489b18673..27b0edd9222 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.Drawing.Interop; +using System.Windows.Forms.Analyzers.Diagnostics; using Microsoft.Win32; namespace System.Windows.Forms.VisualStyles; @@ -65,6 +66,32 @@ public static bool IsSupported } } + [Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)] + /// + /// Returns true if Dark Mode visual styles subclass are 1) supported by the OS 2) enabled in the client area + /// and 3) currently applied to this application. Otherwise, it returns false. Note that + /// if it returns false, attempting to instantiate/use objects of this class + /// will result in exceptions being thrown. + /// + public static bool IsDarkModeSupported + { + get + { + bool supported = AreClientAreaVisualStylesSupported; + + if (supported) + { + // In some cases, this check isn't enough, since the theme handle creation + // could fail for some other reason. Try creating a theme handle here - if successful, return true, + // else return false. + IntPtr hTheme = GetHandle("DarkMode_Explorer::BUTTON", false); // Button is an arbitrary choice. + supported = hTheme != IntPtr.Zero; + } + + return supported; + } + } + /// /// Returns true if the element is defined by the current visual style, else false. /// Note: From cabfc15decf4762ee5ee63e3aab87e6580b77709 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Sun, 25 Aug 2024 21:09:51 +0300 Subject: [PATCH 4/8] Fix build errors --- src/System.Windows.Forms/src/System/Windows/Forms/Control.cs | 2 +- .../Forms/Controls/DataGridView/DataGridViewButtonCell.cs | 1 - ...ViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs | 1 - .../System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index 3e63bc0b709..9fe370c0365 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -163,7 +163,7 @@ public unsafe partial class Control : internal const string ExplorerThemeIdentifier = "Explorer"; internal const string ItemsViewThemeIdentifier = "ItemsView"; internal const string ComboBoxButtonThemeIdentifier = "CFD"; - internal const string TabThemeIdentifier = "FileExplorerBannerContainer"; + internal const string TabThemeIdentifier = "FileExplorerBannerContainer"; private const short PaintLayerBackground = 1; private const short PaintLayerForeground = 2; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs index 0b642422bde..ae9207af716 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewButtonCell.cs @@ -23,7 +23,6 @@ public partial class DataGridViewButtonCell : DataGridViewCell private static readonly VisualStyleElement s_buttonElement = Application.IsDarkModeEnabled ? s_darkButtonElement : s_lightButtonElement; #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. - private const byte DATAGRIDVIEWBUTTONCELL_themeMargin = 100; // Used to calculate the margins required for theming rendering private const byte DATAGRIDVIEWBUTTONCELL_horizontalTextMargin = 2; private const byte DATAGRIDVIEWBUTTONCELL_verticalTextMargin = 1; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs index e1ba42a6242..709bdd59d92 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs @@ -22,7 +22,6 @@ public static VisualStyleRenderer VisualStyleRenderer : VisualStyleElement.Header.Item.Normal); #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 s_visualStyleRenderer; } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs index 27b0edd9222..d5bde69a62a 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs @@ -66,13 +66,13 @@ public static bool IsSupported } } - [Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)] /// /// Returns true if Dark Mode visual styles subclass are 1) supported by the OS 2) enabled in the client area /// and 3) currently applied to this application. Otherwise, it returns false. Note that /// if it returns false, attempting to instantiate/use objects of this class /// will result in exceptions being thrown. /// + [Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)] public static bool IsDarkModeSupported { get From 9c93f8cb8bd9db0cfb8544972b197f57dc7a2d32 Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Tue, 3 Sep 2024 19:43:17 +0300 Subject: [PATCH 5/8] Update src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs Co-authored-by: Loni Tra --- .../System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs index d5bde69a62a..47fa4869b57 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs @@ -84,8 +84,8 @@ public static bool IsDarkModeSupported // In some cases, this check isn't enough, since the theme handle creation // could fail for some other reason. Try creating a theme handle here - if successful, return true, // else return false. - IntPtr hTheme = GetHandle("DarkMode_Explorer::BUTTON", false); // Button is an arbitrary choice. - supported = hTheme != IntPtr.Zero; + HTHEME hTheme = GetHandle("DarkMode_Explorer::BUTTON", false); // Button is an arbitrary choice. + supported = !hTheme.IsNull; } return supported; From a0d17a3b4e29dd43d11f2c3aa966157fa2b458af Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Wed, 4 Sep 2024 00:18:49 +0300 Subject: [PATCH 6/8] Add reviewer recommendations --- .../src/System/Windows/Forms/Control.cs | 3 ++- .../Controls/ComboBox/ComboBoxRenderer.cs | 4 ++-- .../DataGridView/DataGridViewCheckBoxCell.cs | 7 +++--- ...ll.DataGridViewColumnHeaderCellRenderer.cs | 4 ++-- .../DataGridViewColumnHeaderCell.cs | 4 ++-- ...oxCell.DataGridViewComboBoxCellRenderer.cs | 18 +++++++-------- .../DataGridView/DataGridViewRowHeaderCell.cs | 4 ++-- .../DataGridViewTopLeftHeaderCell.cs | 4 ++-- .../Forms/Controls/TabControl/TabControl.cs | 2 +- .../Forms/Controls/TabControl/TabRenderer.cs | 2 +- .../Forms/VisualStyles/VisualStyleRenderer.cs | 23 +++++++++++-------- 11 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs index 9fe370c0365..0fa2de86f4d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Control.cs @@ -163,7 +163,8 @@ public unsafe partial class Control : internal const string ExplorerThemeIdentifier = "Explorer"; internal const string ItemsViewThemeIdentifier = "ItemsView"; internal const string ComboBoxButtonThemeIdentifier = "CFD"; - internal const string TabThemeIdentifier = "FileExplorerBannerContainer"; + internal const string BannerContainerThemeIdentifier = "FileExplorerBannerContainer"; + internal const string NavPaneThemeIdentifier = "ExplorerNavPane"; private const short PaintLayerBackground = 1; private const short PaintLayerForeground = 2; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs index 3508e526c5b..0147f232fd2 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ComboBox/ComboBoxRenderer.cs @@ -15,8 +15,8 @@ public static class ComboBoxRenderer [ThreadStatic] private static VisualStyleRenderer? t_visualStyleRenderer; #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. - private static readonly VisualStyleElement s_comboBoxElement = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 1, 1) + private static readonly VisualStyleElement s_comboBoxElement = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ComboBoxButtonThemeIdentifier}::COMBOBOX", 1, 1) : VisualStyleElement.ComboBox.DropDownButton.Normal; #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. private static readonly VisualStyleElement s_textBoxElement = VisualStyleElement.TextBox.TextEdit.Normal; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs index 79ca2ba0031..957cddf5261 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewCheckBoxCell.cs @@ -21,12 +21,13 @@ public partial class DataGridViewCheckBoxCell : DataGridViewCell, IDataGridViewE private const DataGridViewContentAlignment AnyMiddle = DataGridViewContentAlignment.MiddleRight | DataGridViewContentAlignment.MiddleCenter | DataGridViewContentAlignment.MiddleLeft; #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. - private static readonly VisualStyleElement s_darkCheckBoxElement = VisualStyleElement.CreateElement("DarkMode_Explorer::BUTTON", 3, 1); + private static readonly VisualStyleElement s_darkCheckBoxElement = VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ExplorerThemeIdentifier}::BUTTON", 3, 1); private static readonly VisualStyleElement s_lightCheckBoxElement = VisualStyleElement.Button.CheckBox.UncheckedNormal; - private static readonly VisualStyleElement s_checkBoxElement = Application.IsDarkModeEnabled ? s_darkCheckBoxElement : s_lightCheckBoxElement; + private static readonly VisualStyleElement s_checkBoxElement = Application.IsDarkModeEnabled + ? s_darkCheckBoxElement + : s_lightCheckBoxElement; #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. - private static readonly int s_propButtonCellState = PropertyStore.CreateKey(); private static readonly int s_propTrueValue = PropertyStore.CreateKey(); private static readonly int s_propFalseValue = PropertyStore.CreateKey(); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs index 709bdd59d92..b3957afe13e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.DataGridViewColumnHeaderCellRenderer.cs @@ -17,8 +17,8 @@ public static VisualStyleRenderer VisualStyleRenderer get { #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. - s_visualStyleRenderer ??= new VisualStyleRenderer(Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + s_visualStyleRenderer ??= new VisualStyleRenderer(Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ItemsViewThemeIdentifier}::Header", 1, 1) : VisualStyleElement.Header.Item.Normal); #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. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs index 28d895060ea..3cec23dbcd5 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewColumnHeaderCell.cs @@ -12,8 +12,8 @@ namespace System.Windows.Forms; public partial class DataGridViewColumnHeaderCell : DataGridViewHeaderCell { #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. - private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ItemsViewThemeIdentifier}::Header", 1, 1) : VisualStyleElement.Header.Item.Normal; #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. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs index 2cf292d6cb4..3cf2fd860b9 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewComboBoxCell.DataGridViewComboBoxCellRenderer.cs @@ -13,26 +13,26 @@ private static class DataGridViewComboBoxCellRenderer [ThreadStatic] private static VisualStyleRenderer? t_visualStyleRenderer; #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. - private static readonly VisualStyleElement s_comboBoxBorder = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 4, 1) + private static readonly VisualStyleElement s_comboBoxBorder = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ComboBoxButtonThemeIdentifier}::COMBOBOX", 4, 1) : VisualStyleElement.ComboBox.Border.Normal; #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. #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. - private static readonly VisualStyleElement s_comboBoxDropDownButtonRight = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 6, 1) + private static readonly VisualStyleElement s_comboBoxDropDownButtonRight = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ComboBoxButtonThemeIdentifier}::COMBOBOX", 6, 1) : VisualStyleElement.ComboBox.DropDownButtonRight.Normal; #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. #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. - private static readonly VisualStyleElement s_comboBoxDropDownButtonLeft = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 7, 1) : - VisualStyleElement.ComboBox.DropDownButtonLeft.Normal; + private static readonly VisualStyleElement s_comboBoxDropDownButtonLeft = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ComboBoxButtonThemeIdentifier}::COMBOBOX", 7, 1) + : VisualStyleElement.ComboBox.DropDownButtonLeft.Normal; #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. #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. - private static readonly VisualStyleElement s_comboBoxReadOnlyButton = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_CFD::COMBOBOX", 5, 1) + private static readonly VisualStyleElement s_comboBoxReadOnlyButton = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ComboBoxButtonThemeIdentifier}::COMBOBOX", 5, 1) : VisualStyleElement.ComboBox.ReadOnlyButton.Normal; #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. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs index 15ef40f698f..67e0cafbc87 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewRowHeaderCell.cs @@ -12,8 +12,8 @@ namespace System.Windows.Forms; public partial class DataGridViewRowHeaderCell : DataGridViewHeaderCell { #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. - private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ItemsViewThemeIdentifier}::Header", 1, 1) : VisualStyleElement.Header.Item.Normal; #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. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs index 1711106de02..d3128a362f0 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/DataGridView/DataGridViewTopLeftHeaderCell.cs @@ -9,8 +9,8 @@ namespace System.Windows.Forms; public partial class DataGridViewTopLeftHeaderCell : DataGridViewColumnHeaderCell { #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. - private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled ? - VisualStyleElement.CreateElement("DarkMode_ItemsView::Header", 1, 1) + private static readonly VisualStyleElement s_headerElement = Application.IsDarkModeEnabled + ? VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}_{Control.ItemsViewThemeIdentifier}::Header", 1, 1) : VisualStyleElement.Header.Item.Normal; #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. diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs index 6e10bc83c48..f8425159126 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabControl.cs @@ -1303,7 +1303,7 @@ protected override void OnHandleCreated(EventArgs e) _ = PInvoke.SetWindowTheme( hwnd: HWND, pszSubAppName: null, - pszSubIdList: $"{DarkModeIdentifier}::{TabThemeIdentifier}"); + pszSubIdList: $"{DarkModeIdentifier}::{BannerContainerThemeIdentifier}"); } #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. } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs index 17bcb8a3b35..aed81f3e775 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs @@ -146,7 +146,7 @@ internal static void DrawTabPage(IDeviceContext deviceContext, Rectangle bounds) #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. // Using DarkMode Theme Subclass. // see https://learn.microsoft.com/en-us/windows/win32/controls/theme-subclasses. - VisualStyleElement darkTabPaneElement = VisualStyleElement.CreateElement("DarkMode::ExplorerNavPane", 0, 0); + VisualStyleElement darkTabPaneElement = VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}::{Control.NavPaneThemeIdentifier}", 0, 0); VisualStyleElement lightTabPaneElement = VisualStyleElement.Tab.Pane.Normal; VisualStyleElement tabPaneElement = Application.IsDarkModeEnabled ? darkTabPaneElement diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs index 47fa4869b57..32779b4c451 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs @@ -67,10 +67,18 @@ public static bool IsSupported } /// - /// Returns true if Dark Mode visual styles subclass are 1) supported by the OS 2) enabled in the client area - /// and 3) currently applied to this application. Otherwise, it returns false. Note that - /// if it returns false, attempting to instantiate/use objects of this class - /// will result in exceptions being thrown. + /// + /// Gets a value specifying whether the operating system has Dark Mode visual styles subclass and the Application can use this subclass to draw controls with Dark Mode theme. + /// + /// + /// + /// Returns true if Visual Style Dark Mode subclass is: + /// 1) Supported by the operating system. + /// 2) Enabled in the client area. + /// 3) operating system not ruining in high contrast mode + /// Otherwise, returns false. Note that if false is returned, attempts to create/use objects of this class will throw exceptions. + /// + /// /// [Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)] public static bool IsDarkModeSupported @@ -81,11 +89,8 @@ public static bool IsDarkModeSupported if (supported) { - // In some cases, this check isn't enough, since the theme handle creation - // could fail for some other reason. Try creating a theme handle here - if successful, return true, - // else return false. - HTHEME hTheme = GetHandle("DarkMode_Explorer::BUTTON", false); // Button is an arbitrary choice. - supported = !hTheme.IsNull; + IntPtr hTheme = GetHandle($"{Control.DarkModeIdentifier}_{Control.ExplorerThemeIdentifier}::BUTTON", false); // Button is an arbitrary choice. + supported = hTheme != IntPtr.Zero && !SystemInformation.HighContrast; } return supported; From fe55b13c89ed1fc96e20a172bec4e07494fb9a3d Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Wed, 4 Sep 2024 01:14:36 +0300 Subject: [PATCH 7/8] Update src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs Co-authored-by: Igor Velikorossov --- .../src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs index aed81f3e775..3bf92035501 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TabControl/TabRenderer.cs @@ -145,7 +145,7 @@ internal static void DrawTabPage(IDeviceContext deviceContext, Rectangle bounds) { #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. // Using DarkMode Theme Subclass. - // see https://learn.microsoft.com/en-us/windows/win32/controls/theme-subclasses. + // see https://learn.microsoft.com/windows/win32/controls/theme-subclasses. VisualStyleElement darkTabPaneElement = VisualStyleElement.CreateElement($"{Control.DarkModeIdentifier}::{Control.NavPaneThemeIdentifier}", 0, 0); VisualStyleElement lightTabPaneElement = VisualStyleElement.Tab.Pane.Normal; VisualStyleElement tabPaneElement = Application.IsDarkModeEnabled From 3f9b43499cb7e384bbe412b2035d571661d4f6fb Mon Sep 17 00:00:00 2001 From: Mohmed abdel-fattah Date: Wed, 4 Sep 2024 01:30:58 +0300 Subject: [PATCH 8/8] Reapply lonitra recommendation about "HTHEME" --- .../System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs index 32779b4c451..749cb4281ad 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/VisualStyles/VisualStyleRenderer.cs @@ -89,8 +89,8 @@ public static bool IsDarkModeSupported if (supported) { - IntPtr hTheme = GetHandle($"{Control.DarkModeIdentifier}_{Control.ExplorerThemeIdentifier}::BUTTON", false); // Button is an arbitrary choice. - supported = hTheme != IntPtr.Zero && !SystemInformation.HighContrast; + HTHEME hTheme = GetHandle($"{Control.DarkModeIdentifier}_{Control.ExplorerThemeIdentifier}::BUTTON", false); // Button is an arbitrary choice. + supported = !hTheme.IsNull && !SystemInformation.HighContrast; } return supported;