WinUI3中使用SetWindowCompositionAttribute设置任务栏颜色后点击开始按钮复原问题
任务栏颜色点击「开始」按钮后恢复默认的解决方法
问题分析
使用SetWindowCompositionAttribute修改任务栏颜色后,点击「开始」按钮颜色会恢复系统默认,本质原因是打开开始菜单时,Windows Shell(explorer.exe)会重新加载系统主题配置,覆盖通过API手动设置的任务栏颜色属性。
解决方案
通过监听系统主题偏好变化事件,或在开始菜单交互完成后重新应用自定义颜色,即可保持任务栏的自定义颜色状态。以下提供两种可行方案:
方案1:监听系统偏好变更事件
利用.NET内置的SystemEvents.UserPreferenceChanged事件,当主题或颜色相关设置发生变化时,自动重新应用自定义任务栏颜色。
代码实现
using Microsoft.Win32; using System.Drawing; using System.Runtime.InteropServices; public static class TaskbarColorManager { private static Color _targetColor; static TaskbarColorManager() { // 注册系统偏好变更监听事件 SystemEvents.UserPreferenceChanged += OnUserPreferenceChanged; } public static void SetTaskbarColor(Color color) { _targetColor = color; ApplyTaskbarColor(color); } private static void ApplyTaskbarColor(Color color) { var accentPolicy = default(User32Interop.AccentPolicy); accentPolicy.Color = color.ToAbgr(); accentPolicy.AccentState = 2; accentPolicy.Flags = 2; var data = default(User32Interop.Windowcompositionattribdata); data.Attribute = User32Interop.WindowCompositionAttribute.WcaAccentPolicy; data.SizeOfData = Marshal.SizeOf(typeof(User32Interop.AccentPolicy)); data.Data = Marshal.AllocHGlobal(data.SizeOfData); Marshal.StructureToPtr(accentPolicy, data.Data, false); var taskbarHandle = User32Interop.FindWindow("Shell_TrayWnd", null); var secondaryTaskbarHandle = User32Interop.FindWindow("Shell_SecondaryTrayWnd", null); if (taskbarHandle != nint.Zero) { User32Interop.SetWindowCompositionAttribute(taskbarHandle, ref data); } if (secondaryTaskbarHandle != nint.Zero) { User32Interop.SetWindowCompositionAttribute(secondaryTaskbarHandle, ref data); } Marshal.FreeHGlobal(data.Data); } private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) { // 主题或颜色设置变更时,重新应用自定义颜色 if (e.Category == UserPreferenceCategory.Color || e.Category == UserPreferenceCategory.VisualStyle) { ApplyTaskbarColor(_targetColor); } } // 保留原有的User32互操作定义 public static class User32Interop { [StructLayout(LayoutKind.Sequential)] public struct AccentPolicy { public int AccentState; public int AccentFlags; public int Color; public int AnimationId; } [StructLayout(LayoutKind.Sequential)] public struct Windowcompositionattribdata { public WindowCompositionAttribute Attribute; public nint Data; public int SizeOfData; } public enum WindowCompositionAttribute { WcaAccentPolicy = 19 } [DllImport("user32.dll")] public static extern int SetWindowCompositionAttribute(nint hwnd, ref Windowcompositionattribdata data); [DllImport("user32.dll", SetLastError = true)] public static extern nint FindWindow(string lpClassName, string lpWindowName); } } // 扩展方法:将Color转换为ABGR格式 public static class ColorExtensions { public static int ToAbgr(this Color color) { return (color.A << 24) | (color.B << 16) | (color.G << 8) | color.R; } }
方案2:精准监听开始菜单状态
通过Windows事件钩子监听开始菜单的显示/隐藏事件,在开始菜单关闭后立即重新设置任务栏颜色,仅在点击「开始」按钮的场景下触发重置,更高效精准。
核心思路
- 使用
SetWinEventHook监听EVENT_OBJECT_SHOW和EVENT_OBJECT_HIDE事件,追踪开始菜单窗口(Win10/Win11类名分别为StartMenuHostWnd、Windows.UI.Core.CoreWindow)。 - 检测到开始菜单关闭时,调用
SetTaskbarColor重新应用自定义颜色。
注意事项
- 程序需具备足够权限修改系统UI元素,建议以管理员身份运行测试。
- 不同Windows版本的开始菜单窗口类名存在差异,需根据目标系统版本调整监听的类名。
内容的提问来源于stack exchange,提问作者Jacob Mordon
相关产品推荐
相关产品推荐

