You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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事件钩子监听开始菜单的显示/隐藏事件,在开始菜单关闭后立即重新设置任务栏颜色,仅在点击「开始」按钮的场景下触发重置,更高效精准。

核心思路

  1. 使用SetWinEventHook监听EVENT_OBJECT_SHOW和EVENT_OBJECT_HIDE事件,追踪开始菜单窗口(Win10/Win11类名分别为StartMenuHostWnd、Windows.UI.Core.CoreWindow)。
  2. 检测到开始菜单关闭时,调用SetTaskbarColor重新应用自定义颜色。

注意事项

  • 程序需具备足够权限修改系统UI元素,建议以管理员身份运行测试。
  • 不同Windows版本的开始菜单窗口类名存在差异,需根据目标系统版本调整监听的类名。

内容的提问来源于stack exchange,提问作者Jacob Mordon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:20:57