From 6632fc2817a435b63c66f6100f6b7f08bb926032 Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Fri, 20 Dec 2024 16:15:27 +1000 Subject: [PATCH 01/11] Add ScratchProject2 project for testing #12042 --- .../ScratchProject2/Form1.Designer.cs | 106 ++++++++++++++++ .../IntegrationTests/ScratchProject2/Form1.cs | 23 ++++ .../ScratchProject2/Form1.resx | 120 ++++++++++++++++++ .../ScratchProject2/Program.cs | 20 +++ .../ScratchProject2/ScratchProject2.csproj | 35 +++++ .../ScratchProject2/readme.txt | 1 + 6 files changed, 305 insertions(+) create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.Designer.cs create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.resx create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/ScratchProject2.csproj create mode 100644 src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/readme.txt diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.Designer.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.Designer.cs new file mode 100644 index 00000000000..20afa170cc2 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.Designer.cs @@ -0,0 +1,106 @@ +namespace ScratchProject2 +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + TreeNode treeNode1 = new TreeNode("Node1"); + TreeNode treeNode2 = new TreeNode("Node0", new TreeNode[] { treeNode1 }); + TreeNode treeNode3 = new TreeNode("Node3"); + TreeNode treeNode4 = new TreeNode("Node4"); + TreeNode treeNode5 = new TreeNode("Node5"); + TreeNode treeNode6 = new TreeNode("Node2", new TreeNode[] { treeNode3, treeNode4, treeNode5 }); + TreeNode treeNode7 = new TreeNode("Node6"); + ListViewItem listViewItem1 = new ListViewItem(new string[] { "1", "q", "w", "e" }, -1); + ListViewItem listViewItem2 = new ListViewItem(new string[] { "2", "a", "s", "d" }, -1); + ListViewItem listViewItem3 = new ListViewItem(new string[] { "3", "z", "x", "c" }, -1); + treeView1 = new TreeView(); + listView1 = new ListView(); + columnHeader1 = new ColumnHeader(); + columnHeader2 = new ColumnHeader(); + columnHeader3 = new ColumnHeader(); + SuspendLayout(); + // + // treeView1 + // + treeView1.LabelEdit = true; + treeView1.Location = new Point(24, 59); + treeView1.Name = "treeView1"; + treeNode1.Name = "Node1"; + treeNode1.Text = "Node1"; + treeNode2.Name = "Node0"; + treeNode2.Text = "Node0"; + treeNode3.Name = "Node3"; + treeNode3.Text = "Node3"; + treeNode4.Name = "Node4"; + treeNode4.Text = "Node4"; + treeNode5.Name = "Node5"; + treeNode5.Text = "Node5"; + treeNode6.Name = "Node2"; + treeNode6.Text = "Node2"; + treeNode7.Name = "Node6"; + treeNode7.Text = "Node6"; + treeView1.Nodes.AddRange(new TreeNode[] { treeNode2, treeNode6, treeNode7 }); + treeView1.Size = new Size(161, 199); + treeView1.TabIndex = 0; + + + // + // listView1 + // + listView1.Columns.AddRange(new ColumnHeader[] { columnHeader1, columnHeader2, columnHeader3 }); + listView1.Items.AddRange(new ListViewItem[] { listViewItem1, listViewItem2, listViewItem3 }); + listView1.LabelEdit = true; + listView1.Location = new Point(254, 61); + listView1.Name = "listView1"; + listView1.Size = new Size(159, 160); + listView1.TabIndex = 1; + listView1.UseCompatibleStateImageBehavior = false; + listView1.View = View.Details; + // + // Form1 + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(591, 334); + Controls.Add(listView1); + Controls.Add(treeView1); + Name = "Form1"; + Text = "Form1"; + ResumeLayout(false); + } + + #endregion + + private TreeView treeView1; + private ListView listView1; + + private ColumnHeader columnHeader1; + private ColumnHeader columnHeader2; + private ColumnHeader columnHeader3; + } +} diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs new file mode 100644 index 00000000000..c6fbad07b6c --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs @@ -0,0 +1,23 @@ + +namespace ScratchProject2 +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + Load += Form1_Load; + } + + private void Form1_Load(object? sender, EventArgs e) + { + treeView1.BeforeLabelEdit += treeView1_BeforeLabelEdit; + } + + private void treeView1_BeforeLabelEdit(object? sender, NodeLabelEditEventArgs e) + { + Console.WriteLine("Here!"); + } + + } +} diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.resx b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.resx new file mode 100644 index 00000000000..8b2ff64a113 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs new file mode 100644 index 00000000000..1a7e680f92f --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace ScratchProject2; + +// This project is meant for temporary testing and experimenting and should be kept as simple as possible. + +internal static class Program +{ + [STAThread] + public static void Main() + { + Application.EnableVisualStyles(); + Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); +#pragma warning disable WFO5001 + Application.SetColorMode(SystemColorMode.Dark); + Form1 form = new(); + Application.Run(form); + } +} diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/ScratchProject2.csproj b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/ScratchProject2.csproj new file mode 100644 index 00000000000..3d6e407ec73 --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/ScratchProject2.csproj @@ -0,0 +1,35 @@ + + + + WinExe + enable + enable + true + true + + false + false + true + + + + + false + false + win-x64 + False + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/readme.txt b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/readme.txt new file mode 100644 index 00000000000..739914eee0e --- /dev/null +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/readme.txt @@ -0,0 +1 @@ +This project is meant for doing temporary testing and should be left as simple and basic as possible. \ No newline at end of file From b384b6031d7898cdb11286c53486964835f2741b Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Fri, 20 Dec 2024 19:08:21 +1000 Subject: [PATCH 02/11] Probably needs a form handle rather than a label handle. --- Winforms.sln | 18 +++++++ .../Forms/Controls/TreeView/TreeView.cs | 48 +++++++++++++++++++ .../ScratchProject2/Program.cs | 1 + 3 files changed, 67 insertions(+) diff --git a/Winforms.sln b/Winforms.sln index c012dd45fe1..cfb4c21583a 100644 --- a/Winforms.sln +++ b/Winforms.sln @@ -202,6 +202,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Private.Windows.GdiPlus", "src\System.Private.Windows.GdiPlus\System.Private.Windows.GdiPlus.csproj", "{442C867C-51C0-8CE5-F067-DF065008E3DA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScratchProject2", "src\System.Windows.Forms\tests\IntegrationTests\ScratchProject2\ScratchProject2.csproj", "{9A195C79-D335-485B-B5AB-9A1EF1F9E58A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1102,6 +1104,22 @@ Global {442C867C-51C0-8CE5-F067-DF065008E3DA}.Release|x64.Build.0 = Release|Any CPU {442C867C-51C0-8CE5-F067-DF065008E3DA}.Release|x86.ActiveCfg = Release|Any CPU {442C867C-51C0-8CE5-F067-DF065008E3DA}.Release|x86.Build.0 = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|arm64.ActiveCfg = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|arm64.Build.0 = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|x64.ActiveCfg = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|x64.Build.0 = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|x86.ActiveCfg = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Debug|x86.Build.0 = Debug|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|Any CPU.Build.0 = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|arm64.ActiveCfg = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|arm64.Build.0 = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|x64.ActiveCfg = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|x64.Build.0 = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|x86.ActiveCfg = Release|Any CPU + {9A195C79-D335-485B-B5AB-9A1EF1F9E58A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index a7e66b35eb7..507a1a63a30 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -12,6 +12,10 @@ using Windows.Win32.UI.Accessibility; using static System.Windows.Forms.TreeNode; + + + + namespace System.Windows.Forms; /// @@ -2579,7 +2583,51 @@ private LRESULT TvnBeginLabelEdit(NMTVDISPINFOW nmtvdi) if (!e.CancelEdit) { _labelEdit = new TreeViewLabelEditNativeWindow(this); + _labelEdit.AssignHandle(PInvokeCore.SendMessage(this, PInvoke.TVM_GETEDITCONTROL)); + + // Force dark mode on editing label if necessary + [DllImport("dwmapi.dll", PreserveSig = false)] + static extern void DwmSetWindowAttribute(IntPtr hwnd, int attr, + ref int attrValue, int attrSize); + +#pragma warning disable WFO5001 + SystemColorMode thisColorMode; + if (Application.ColorMode == SystemColorMode.System) + { + thisColorMode = Application.SystemColorMode; + } + else + { + thisColorMode = Application.ColorMode; + } + + if (thisColorMode == SystemColorMode.Dark) + { + int trueVal = 1; + const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; + + IntPtr handle = _labelEdit.Handle; + Debug.WriteLine(handle.ToString()); + + try + { + DwmSetWindowAttribute(handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref trueVal, sizeof(int)); + } + catch (Exception dwmEx) + { + string msg = dwmEx.Message; + if (dwmEx.InnerException is not null) + { + msg = msg + Environment.NewLine + dwmEx.InnerException.Message; + } + + Debug.WriteLine(msg); + } + + } + +#pragma warning restore WFO5001 } return (LRESULT)(e.CancelEdit ? 1 : 0); diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs index 1a7e680f92f..21365c6d7c4 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs @@ -14,6 +14,7 @@ public static void Main() Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); #pragma warning disable WFO5001 Application.SetColorMode(SystemColorMode.Dark); +#pragma warning restore WFO5001 Form1 form = new(); Application.Run(form); } From 5ac73f9cf3006fd60fec261c4bb5b45840d09dd2 Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Fri, 20 Dec 2024 21:01:50 +1000 Subject: [PATCH 03/11] Set to try different DWM values and calls. --- .../Forms/Controls/TreeView/TreeView.cs | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 507a1a63a30..ed065c540fe 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2555,6 +2555,38 @@ private unsafe void TvnSelected(NMTREEVIEWW* nmtv) } } + private enum DWMWINDOWATTRIBUTE + { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY, + DWMWA_TRANSITIONS_FORCEDISABLED, + DWMWA_ALLOW_NCPAINT, + DWMWA_CAPTION_BUTTON_BOUNDS, + DWMWA_NONCLIENT_RTL_LAYOUT, + DWMWA_FORCE_ICONIC_REPRESENTATION, + DWMWA_FLIP3D_POLICY, + DWMWA_EXTENDED_FRAME_BOUNDS, + DWMWA_HAS_ICONIC_BITMAP, + DWMWA_DISALLOW_PEEK, + DWMWA_EXCLUDED_FROM_PEEK, + DWMWA_CLOAK, + DWMWA_CLOAKED, + DWMWA_FREEZE_REPRESENTATION, + DWMWA_PASSIVE_UPDATE_MODE, + DWMWA_USE_HOSTBACKDROPBRUSH, + DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19, + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + DWMWA_WINDOW_CORNER_PREFERENCE = 33, + DWMWA_BORDER_COLOR, + DWMWA_CAPTION_COLOR, + DWMWA_TEXT_COLOR, + DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, + DWMWA_SYSTEMBACKDROP_TYPE, + DWMWA_LAST + } + + + private LRESULT TvnBeginLabelEdit(NMTVDISPINFOW nmtvdi) { // Check for invalid node handle @@ -2604,15 +2636,21 @@ static extern void DwmSetWindowAttribute(IntPtr hwnd, int attr, if (thisColorMode == SystemColorMode.Dark) { - int trueVal = 1; - const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; - IntPtr handle = _labelEdit.Handle; - Debug.WriteLine(handle.ToString()); try { - DwmSetWindowAttribute(handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref trueVal, sizeof(int)); + // Try different dwm attributes and values + // May be a problem with WIN 10 compatibility + + int trueVal = 1; + var attr = (int)DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR; + var attrVal = 0x00ff0000; + + IntPtr handle = _labelEdit.Handle; + Debug.WriteLine(handle.ToString()); + + DwmSetWindowAttribute(handle, attr, ref attrVal, Marshal.SizeOf(attrVal) ); } catch (Exception dwmEx) { From 513ab3e08aaba29f3857638a1afaf2013b3358ae Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Fri, 20 Dec 2024 22:05:24 +1000 Subject: [PATCH 04/11] Loop through possible WindowAttribute values for future analysis. --- .../Forms/Controls/TreeView/TreeView.cs | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index ed065c540fe..6da2016f137 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2638,33 +2638,51 @@ static extern void DwmSetWindowAttribute(IntPtr hwnd, int attr, { - try - { // Try different dwm attributes and values // May be a problem with WIN 10 compatibility - int trueVal = 1; - var attr = (int)DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR; - var attrVal = 0x00ff0000; + //int trueVal = 1; + + //var attr = (int)DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR; + //var attrVal = 0x00ff0000; IntPtr handle = _labelEdit.Handle; Debug.WriteLine(handle.ToString()); - DwmSetWindowAttribute(handle, attr, ref attrVal, Marshal.SizeOf(attrVal) ); - } - catch (Exception dwmEx) + for (int attrVal = 0; attrVal <= 10; attrVal++) + { - string msg = dwmEx.Message; - if (dwmEx.InnerException is not null) + Debug.WriteLine(""); + + for (int attr = 1; attr <= 50; attr++) { - msg = msg + Environment.NewLine + dwmEx.InnerException.Message; + Debug.WriteLine(""); + try + { + + DwmSetWindowAttribute(handle, attr, ref attrVal, Marshal.SizeOf(attrVal)); + + + } + catch (Exception dwmEx) + { + string msg = dwmEx.Message; + if (dwmEx.InnerException is not null) + { + msg = msg + Environment.NewLine + dwmEx.InnerException.Message; + } + + Debug.WriteLine("Attribute:" + attr.ToString()); + Debug.WriteLine("Attr Valu:" + attrVal.ToString()); + Debug.WriteLine(msg); + } } - - Debug.WriteLine(msg); } - } + // do I need to invalidate to get an update? + + #pragma warning restore WFO5001 } From 361002305a26803fdaa9a0508888bd3476bbb3df Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 11:11:25 +1000 Subject: [PATCH 05/11] Attempt to set edit box color through WmNotify --- .../Forms/Controls/TreeView/TreeView.cs | 26 ++++++++++++++++++- .../IntegrationTests/ScratchProject2/Form1.cs | 4 ++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 6da2016f137..af208fdac2f 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2617,7 +2617,11 @@ private LRESULT TvnBeginLabelEdit(NMTVDISPINFOW nmtvdi) _labelEdit = new TreeViewLabelEditNativeWindow(this); _labelEdit.AssignHandle(PInvokeCore.SendMessage(this, PInvoke.TVM_GETEDITCONTROL)); + } + + + /* // Force dark mode on editing label if necessary [DllImport("dwmapi.dll", PreserveSig = false)] static extern void DwmSetWindowAttribute(IntPtr hwnd, int attr, @@ -2684,7 +2688,8 @@ static extern void DwmSetWindowAttribute(IntPtr hwnd, int attr, #pragma warning restore WFO5001 - } + */ + return (LRESULT)(e.CancelEdit ? 1 : 0); } @@ -3102,6 +3107,25 @@ private unsafe void WmNotify(ref Message m) switch (nmtv->hdr.code) { + // Handle setting color of edit box to background color of control + case PInvokeCore.WM_CTLCOLOREDIT: + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern void SetDCBrushColor(HDC hdc, COLORREF attr); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern LRESULT GetStockObject(IntPtr brushType); + + const int DC_BRUSH = 18; + HDC editHDC = (HDC)m.WParamInternal; + HWND editHandle = (HWND)m.LParamInternal; + Color tvColor = BackColor; + SetDCBrushColor(editHDC, tvColor); + LRESULT brush = GetStockObject(DC_BRUSH); + + // Need to return a pointer to a brush + m.ResultInternal = brush; + break; + + case PInvoke.TVN_ITEMEXPANDINGW: m.ResultInternal = (LRESULT)TvnExpanding(nmtv); break; diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs index c6fbad07b6c..5409aa287a4 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs @@ -1,4 +1,6 @@  +using System.Diagnostics; + namespace ScratchProject2 { public partial class Form1 : Form @@ -16,7 +18,7 @@ private void Form1_Load(object? sender, EventArgs e) private void treeView1_BeforeLabelEdit(object? sender, NodeLabelEditEventArgs e) { - Console.WriteLine("Here!"); + Debug.WriteLine("Here!"); } } From 1bc5d82488f39d73247a05915854afaa0c8adf3b Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 13:18:23 +1000 Subject: [PATCH 06/11] This didn't change the color of the background on edit. --- .../Forms/Controls/TreeView/TreeView.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index af208fdac2f..1ca551dffb8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2891,6 +2891,7 @@ private unsafe void CustomDraw(ref Message m) // when one item is selected, click and hold on another). This needs to be fixed. Color riFore = renderinfo.ForeColor; Color riBack = renderinfo.BackColor; + if (renderinfo is not null && !riFore.IsEmpty) { nmtvcd->clrText = ColorTranslator.ToWin32(riFore); @@ -3107,25 +3108,6 @@ private unsafe void WmNotify(ref Message m) switch (nmtv->hdr.code) { - // Handle setting color of edit box to background color of control - case PInvokeCore.WM_CTLCOLOREDIT: - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern void SetDCBrushColor(HDC hdc, COLORREF attr); - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern LRESULT GetStockObject(IntPtr brushType); - - const int DC_BRUSH = 18; - HDC editHDC = (HDC)m.WParamInternal; - HWND editHandle = (HWND)m.LParamInternal; - Color tvColor = BackColor; - SetDCBrushColor(editHDC, tvColor); - LRESULT brush = GetStockObject(DC_BRUSH); - - // Need to return a pointer to a brush - m.ResultInternal = brush; - break; - - case PInvoke.TVN_ITEMEXPANDINGW: m.ResultInternal = (LRESULT)TvnExpanding(nmtv); break; @@ -3288,6 +3270,24 @@ protected override unsafe void WndProc(ref Message m) { switch (m.MsgInternal) { + case PInvokeCore.WM_CTLCOLOREDIT: + // MDO Handle setting color of edit box to background color of control + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern void SetDCBrushColor(HDC hdc, COLORREF attr); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern LRESULT GetStockObject(IntPtr brushType); + + // The WParam seems dodgy + const int DC_BRUSH = 18; + HDC editHDC = (HDC)m.WParamInternal; + HWND editHandle = (HWND)m.LParamInternal; + Color tvColor = BackColor; + SetDCBrushColor(editHDC, tvColor); + LRESULT brush = GetStockObject(DC_BRUSH); + Debug.WriteLine(brush.GetType().ToString()); + // Need to return a pointer to a brush + m.ResultInternal = brush; + break; case PInvokeCore.WM_WINDOWPOSCHANGING: case PInvokeCore.WM_NCCALCSIZE: case PInvokeCore.WM_WINDOWPOSCHANGED: From d8a5fa972fc57c440c0c785c6a5a46cd37617a0c Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 13:43:22 +1000 Subject: [PATCH 07/11] Working for TreeView --- .../Forms/Controls/TreeView/TreeView.cs | 21 ++++++++----------- .../ScratchProject2/Program.cs | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 1ca551dffb8..684816db519 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -3270,23 +3270,20 @@ protected override unsafe void WndProc(ref Message m) { switch (m.MsgInternal) { + // Handle setting color of edit box to background color of parent control + // This makes dark mode edit labels the correct color case PInvokeCore.WM_CTLCOLOREDIT: - // MDO Handle setting color of edit box to background color of control [DllImport("Gdi32.dll", PreserveSig = true)] - static extern void SetDCBrushColor(HDC hdc, COLORREF attr); + static extern HBRUSH CreateSolidBrush(COLORREF color); [DllImport("Gdi32.dll", PreserveSig = true)] - static extern LRESULT GetStockObject(IntPtr brushType); + static extern COLORREF SetBkColor(HDC hdc,COLORREF color); - // The WParam seems dodgy - const int DC_BRUSH = 18; - HDC editHDC = (HDC)m.WParamInternal; - HWND editHandle = (HWND)m.LParamInternal; Color tvColor = BackColor; - SetDCBrushColor(editHDC, tvColor); - LRESULT brush = GetStockObject(DC_BRUSH); - Debug.WriteLine(brush.GetType().ToString()); - // Need to return a pointer to a brush - m.ResultInternal = brush; + HBRUSH hBrush = CreateSolidBrush(tvColor); + HDC editHDC = (HDC)m.WParamInternal; + SetBkColor(editHDC, tvColor); + LRESULT lrBrush = (LRESULT)(IntPtr)hBrush; + m.ResultInternal = lrBrush; break; case PInvokeCore.WM_WINDOWPOSCHANGING: case PInvokeCore.WM_NCCALCSIZE: diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs index 21365c6d7c4..0905d98eae1 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs @@ -13,7 +13,7 @@ public static void Main() Application.EnableVisualStyles(); Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); #pragma warning disable WFO5001 - Application.SetColorMode(SystemColorMode.Dark); + Application.SetColorMode(SystemColorMode.Classic); #pragma warning restore WFO5001 Form1 form = new(); Application.Run(form); From 1e9ba190c7c42562240e3c1f38e25f9a4dbd7bda Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 13:59:35 +1000 Subject: [PATCH 08/11] Restrict Treeview mods to Dark Mode --- .../Forms/Controls/TreeView/TreeView.cs | 34 ++++++++++++------- .../IntegrationTests/ScratchProject2/Form1.cs | 11 ++++-- .../ScratchProject2/Program.cs | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 684816db519..15197688cf8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -3270,20 +3270,28 @@ protected override unsafe void WndProc(ref Message m) { switch (m.MsgInternal) { - // Handle setting color of edit box to background color of parent control - // This makes dark mode edit labels the correct color case PInvokeCore.WM_CTLCOLOREDIT: - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern HBRUSH CreateSolidBrush(COLORREF color); - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern COLORREF SetBkColor(HDC hdc,COLORREF color); - - Color tvColor = BackColor; - HBRUSH hBrush = CreateSolidBrush(tvColor); - HDC editHDC = (HDC)m.WParamInternal; - SetBkColor(editHDC, tvColor); - LRESULT lrBrush = (LRESULT)(IntPtr)hBrush; - m.ResultInternal = lrBrush; + // Default handling of edit label colors + m.ResultInternal = (LRESULT)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. + if (Application.IsDarkModeEnabled) + { + // Make background of dark mode edit labels the correct color + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern HBRUSH CreateSolidBrush(COLORREF color); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern COLORREF SetBkColor(HDC hdc, COLORREF color); + + Color tvColor = BackColor; + HBRUSH hBrush = CreateSolidBrush(tvColor); + HDC editHDC = (HDC)m.WParamInternal; + SetBkColor(editHDC, tvColor); + LRESULT lrBrush = (LRESULT)(IntPtr)hBrush; + m.ResultInternal = lrBrush; + } +#pragma warning restore WFO5001 + + break; case PInvokeCore.WM_WINDOWPOSCHANGING: case PInvokeCore.WM_NCCALCSIZE: diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs index 5409aa287a4..c8d36b187b4 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Form1.cs @@ -14,12 +14,19 @@ public Form1() private void Form1_Load(object? sender, EventArgs e) { treeView1.BeforeLabelEdit += treeView1_BeforeLabelEdit; + listView1.BeforeLabelEdit += listView1_BeforeLabelEdit; } + private void listView1_BeforeLabelEdit(object? sender, LabelEditEventArgs e) + { + Debug.WriteLine("ListView Here!"); + } + + private void treeView1_BeforeLabelEdit(object? sender, NodeLabelEditEventArgs e) { - Debug.WriteLine("Here!"); - } + Debug.WriteLine("TreeView Here!"); + } } } diff --git a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs index 0905d98eae1..21365c6d7c4 100644 --- a/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs +++ b/src/System.Windows.Forms/tests/IntegrationTests/ScratchProject2/Program.cs @@ -13,7 +13,7 @@ public static void Main() Application.EnableVisualStyles(); Application.SetHighDpiMode(HighDpiMode.PerMonitorV2); #pragma warning disable WFO5001 - Application.SetColorMode(SystemColorMode.Classic); + Application.SetColorMode(SystemColorMode.Dark); #pragma warning restore WFO5001 Form1 form = new(); Application.Run(form); From dc7c5ae02e95f1760515f08cd00be47fb21cbf5c Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 14:32:56 +1000 Subject: [PATCH 09/11] Seems to be working for Treeview --- .../Forms/Controls/TreeView/TreeView.cs | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 15197688cf8..c19f3c42909 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -34,6 +34,9 @@ public partial class TreeView : Control private const string BackSlash = "\\"; private const int DefaultTreeViewIndent = 19; + // To hold created dark mode brush for deletion + private HBRUSH _hBrush; + private DrawTreeNodeEventHandler? _onDrawNode; private NodeLabelEditEventHandler? _onBeforeLabelEdit; private NodeLabelEditEventHandler? _onAfterLabelEdit; @@ -2106,6 +2109,11 @@ protected virtual void OnAfterLabelEdit(NodeLabelEditEventArgs e) { e.Node.AccessibilityObject?.RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); } + + // Delete created _hBrush if it exists + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern void DeleteObject(HGDIOBJ ho); + DeleteObject(_hBrush); } /// @@ -3277,17 +3285,43 @@ protected override unsafe void WndProc(ref Message m) if (Application.IsDarkModeEnabled) { // Make background of dark mode edit labels the correct color + + /* + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern void SetDCBrushColor(HDC hdc, COLORREF attr); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern HGDIOBJ GetStockObject(IntPtr brushType); + [DllImport("User32.dll", PreserveSig = true)] + static extern HBRUSH GetSysColorBrush(SYS_COLOR_INDEX index); + + const int DC_BRUSH = 18; + HDC editHDC = (HDC)m.WParamInternal; + HWND editHandle = (HWND)m.LParamInternal; + Color tvColor = BackColor; + SetDCBrushColor(editHDC, tvColor); + //HGDIOBJ brush = GetStockObject(DC_BRUSH); + HBRUSH brush = GetSysColorBrush(SYS_COLOR_INDEX.COLOR_WINDOW); + // Need to return a pointer to a brush + LRESULT lrBrush = (LRESULT)(IntPtr)brush; + m.ResultInternal = lrBrush; + */ + [DllImport("Gdi32.dll", PreserveSig = true)] static extern HBRUSH CreateSolidBrush(COLORREF color); [DllImport("Gdi32.dll", PreserveSig = true)] static extern COLORREF SetBkColor(HDC hdc, COLORREF color); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern COLORREF SetTextColor(HDC hdc, COLORREF color); Color tvColor = BackColor; - HBRUSH hBrush = CreateSolidBrush(tvColor); + Color tvTextColor = ForeColor; + _hBrush = CreateSolidBrush(tvColor); HDC editHDC = (HDC)m.WParamInternal; SetBkColor(editHDC, tvColor); - LRESULT lrBrush = (LRESULT)(IntPtr)hBrush; + SetTextColor(editHDC, tvTextColor); + LRESULT lrBrush = (LRESULT)(IntPtr)_hBrush; m.ResultInternal = lrBrush; + } #pragma warning restore WFO5001 From 06d0e268e0368aaef7bfaf93e3f6e9a09106947b Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 14:58:49 +1000 Subject: [PATCH 10/11] Changes to ListView for dark mode listitem editing --- .../Forms/Controls/ListView/ListView.cs | 36 +++++++++++++++++++ .../Forms/Controls/TreeView/TreeView.cs | 22 ------------ 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs index 5949a52df76..0f613083e02 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs @@ -56,6 +56,9 @@ public partial class ListView : Control private View _viewStyle = View.LargeIcon; private string? _toolTipCaption = string.Empty; + // To hold created dark mode brush for deletion + private HBRUSH _hBrush; + private const int LISTVIEWSTATE_ownerDraw = 0x00000001; private const int LISTVIEWSTATE_allowColumnReorder = 0x00000002; private const int LISTVIEWSTATE_autoArrange = 0x00000004; @@ -4331,6 +4334,12 @@ internal void ListViewItemToolTipChanged(ListViewItem item) protected virtual void OnAfterLabelEdit(LabelEditEventArgs e) { _onAfterLabelEdit?.Invoke(this, e); + + // Delete created _hBrush if it exists + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern void DeleteObject(HGDIOBJ ho); + DeleteObject(_hBrush); + } protected override void OnBackgroundImageChanged(EventArgs e) @@ -6908,6 +6917,33 @@ protected override void WndProc(ref Message m) { switch (m.MsgInternal) { + case PInvokeCore.WM_CTLCOLOREDIT: + // Default handling of edit label colors + m.ResultInternal = (LRESULT)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. + if (Application.IsDarkModeEnabled) + { + // Make background of dark mode edit labels the correct color + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern HBRUSH CreateSolidBrush(COLORREF color); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern COLORREF SetBkColor(HDC hdc, COLORREF color); + [DllImport("Gdi32.dll", PreserveSig = true)] + static extern COLORREF SetTextColor(HDC hdc, COLORREF color); + + Color tvColor = BackColor; + Color tvTextColor = ForeColor; + _hBrush = CreateSolidBrush(tvColor); + HDC editHDC = (HDC)m.WParamInternal; + SetBkColor(editHDC, tvColor); + SetTextColor(editHDC, tvTextColor); + LRESULT lrBrush = (LRESULT)(IntPtr)_hBrush; + m.ResultInternal = lrBrush; + } +#pragma warning restore WFO5001 + + + break; case MessageId.WM_REFLECT_NOTIFY: WmReflectNotify(ref m); break; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index c19f3c42909..6fd57bf7879 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -3285,27 +3285,6 @@ protected override unsafe void WndProc(ref Message m) if (Application.IsDarkModeEnabled) { // Make background of dark mode edit labels the correct color - - /* - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern void SetDCBrushColor(HDC hdc, COLORREF attr); - [DllImport("Gdi32.dll", PreserveSig = true)] - static extern HGDIOBJ GetStockObject(IntPtr brushType); - [DllImport("User32.dll", PreserveSig = true)] - static extern HBRUSH GetSysColorBrush(SYS_COLOR_INDEX index); - - const int DC_BRUSH = 18; - HDC editHDC = (HDC)m.WParamInternal; - HWND editHandle = (HWND)m.LParamInternal; - Color tvColor = BackColor; - SetDCBrushColor(editHDC, tvColor); - //HGDIOBJ brush = GetStockObject(DC_BRUSH); - HBRUSH brush = GetSysColorBrush(SYS_COLOR_INDEX.COLOR_WINDOW); - // Need to return a pointer to a brush - LRESULT lrBrush = (LRESULT)(IntPtr)brush; - m.ResultInternal = lrBrush; - */ - [DllImport("Gdi32.dll", PreserveSig = true)] static extern HBRUSH CreateSolidBrush(COLORREF color); [DllImport("Gdi32.dll", PreserveSig = true)] @@ -3321,7 +3300,6 @@ protected override unsafe void WndProc(ref Message m) SetTextColor(editHDC, tvTextColor); LRESULT lrBrush = (LRESULT)(IntPtr)_hBrush; m.ResultInternal = lrBrush; - } #pragma warning restore WFO5001 From 084bbebc10355e2be17c19540c7f5676b23df507 Mon Sep 17 00:00:00 2001 From: Mark Daniel Osborne Date: Sat, 21 Dec 2024 15:29:01 +1000 Subject: [PATCH 11/11] Fix spacing. --- .../src/System/Windows/Forms/Controls/ListView/ListView.cs | 3 +-- .../src/System/Windows/Forms/Controls/TreeView/TreeView.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs index 0f613083e02..0eaefafb3b6 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs @@ -6941,9 +6941,8 @@ protected override void WndProc(ref Message m) m.ResultInternal = lrBrush; } #pragma warning restore WFO5001 - - break; + case MessageId.WM_REFLECT_NOTIFY: WmReflectNotify(ref m); break; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs index 6fd57bf7879..aaf4322ec67 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -3302,9 +3302,8 @@ protected override unsafe void WndProc(ref Message m) m.ResultInternal = lrBrush; } #pragma warning restore WFO5001 - - break; + case PInvokeCore.WM_WINDOWPOSCHANGING: case PInvokeCore.WM_NCCALCSIZE: case PInvokeCore.WM_WINDOWPOSCHANGED: