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

WinUI3运行时修改GradientStop颜色触发COMException问题求助

WinUI 3非打包应用修改GradientStop颜色第二次触发COMException问题

问题场景

在WinUI 3非打包应用(项目文件中WindowsAppSDKIncluded设为true)中,通过Windows.UI.ViewManagement.UISettings的事件响应系统主题切换时,首次启动修改XAML里GradientStop的颜色正常,但第二次修改会触发System.Runtime.InteropServices.COMException in WinRT.Runtime.dll异常。最初尝试使用App.Xaml资源实现,后改用DataHandler类,问题依旧。

相关代码

MainWindow.xaml.cs

public sealed partial class Window : WinUIEx.WindowEx {
    private DataHandler handler;
    private bool isThemeSystem = true;
    // 省略其他代码
}

public Window() {
    handler = new DataHandler();
}

private Windows.UI.Color dyn(string name) {
    return handler.getColor(currentTheme, name);
}

public void setTheme()
{
    if (isThemeSystem)
    {
        try
        {
            currentTheme = Convert.ToInt32(Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize").GetValue("AppsUseLightTheme"));

            gradient0.Color = dyn("gr0");
            gradient1.Color = dyn("gr1");
        } catch (Exception ex) {
            Debug.WriteLine(ex.StackTrace);
        }
    } 
    else
    {
        // 自定义主题逻辑
    }
}

DataHandler.cs

using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Windows.UI;

namespace Hostware
{
    internal class DataHandler
    {
        public static string appData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Hostware");
        private static Dictionary<string, string> list = new Dictionary<string, string>()
        {
            {"l_gr0","#FFFFFF"},
            {"l_gr1","#FFA9A9A9"},
            {"d_gr0","#101010"},
            {"d_gr1","#292929"},
        };

        public DataHandler()
        {
            Debug.WriteLine("Initialized Hostware/DataHandler.cs");
            Directory.CreateDirectory(appData);
        }

        public Windows.UI.Color getColor(int themeInt, string name)
        {
            string extender = string.Empty;
            if (themeInt == 0)
            {
                // 深色主题
                extender = "d_";
            }
            else if (themeInt == 1)
            {
                // 浅色主题
                extender = "l_";
            }
            System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml(list.GetValueOrDefault(extender + name));
            return Windows.UI.Color.FromArgb(255, (byte)color.R, (byte)color.G, (byte)color.B);
        }
    }
}

问题原因

  1. UISettings事件的线程问题:UISettings.ColorValuesChanged事件在非UI线程触发,直接在回调中修改UI元素会导致跨线程访问异常,首次修改可能因线程侥幸未触发,但第二次必然暴露问题。
  2. 颜色转换的潜在风险:混用System.Drawing.Color和Windows.UI.Color可能引发类型转换的隐性问题,加剧异常概率。

解决方案

1. 替换主题变更监听方式

放弃UISettings,改用WinUI 3原生的RequestedThemeChanged事件,该事件在UI线程触发,无需额外线程调度:

protected override void OnActivated(IActivatedEventArgs args)
{
    base.OnActivated(args);
    Application.Current.RequestedThemeChanged += Current_RequestedThemeChanged;
}

private void Current_RequestedThemeChanged(Application sender, RequestedThemeChangedEventArgs args)
{
    setTheme();
}

2. 强制UI操作在UI线程执行(若需保留UISettings)

如果必须使用UISettings,需通过DispatcherQueue将UI操作调度到UI线程:

private async void UISettings_ColorValuesChanged(UISettings sender, object args)
{
    await DispatcherQueue.TryEnqueue(() =>
    {
        setTheme();
    });
}

3. 优化颜色转换逻辑

直接使用WinUI的ColorHelper.TryParseHex方法,避免跨类型转换:

public Windows.UI.Color getColor(int themeInt, string name)
{
    string extender = themeInt == 0 ? "d_" : "l_";
    var hexColor = list.GetValueOrDefault(extender + name);
    
    if (Windows.UI.ColorHelper.TryParseHex(hexColor, out var color))
    {
        color.A = 255;
        return color;
    }
    
    // 回退到默认颜色
    return themeInt == 0 
        ? Windows.UI.Color.FromArgb(255, 16, 16, 16) 
        : Windows.UI.Color.FromArgb(255, 255, 255, 255);
}

验证效果

修改后,每次系统主题切换时,GradientStop颜色修改操作都在UI线程安全执行,不会再触发COMException。

内容的提问来源于stack exchange,提问作者Kalib Story

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:43:14