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); } } }
问题原因
- UISettings事件的线程问题:
UISettings.ColorValuesChanged事件在非UI线程触发,直接在回调中修改UI元素会导致跨线程访问异常,首次修改可能因线程侥幸未触发,但第二次必然暴露问题。 - 颜色转换的潜在风险:混用
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
相关产品推荐
相关产品推荐

