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

WinUI3(.NET8)访问App.xaml的TrayIcon资源触发COMException错误

WinUI 3 (.NET 8) 集成H.NotifyIcon时访问XAML声明的TaskbarIcon资源触发COMException

问题详情

在WinUI 3(.NET 8)项目中集成H.NotifyIcon.WinUI包,参考H.NotifyIcon.Apps.WinUI.Windowless示例实现系统托盘功能时,从App.xaml的ResourceDictionary中访问声明的TaskbarIcon资源时触发运行时错误:

System.Runtime.InteropServices.COMException: 'Unspecified error' (HResult: -2147467259)

错误堆栈:

at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
   at WinRT.DelegateExtensions.DynamicInvokeAbi(Delegate del, Object[] invoke_params)
   at ABI.Windows.Foundation.Collections.IMapMethods`2.Lookup(IObjectReference obj, K key)
   at ABI.System.Collections.Generic.IDictionaryMethods`2.Lookup(IObjectReference obj, K key)
   at ABI.System.Collections.Generic.IDictionaryMethods`2.Indexer_Get(IObjectReference obj, Dictionary`2 __lookupCache, K key)
   at Microsoft.UI.Xaml.ResourceDictionary.get_Item(Object key)
   at Project.App.OnLaunched(LaunchActivatedEventArgs args) in C:\Project\App.xaml.cs:line 38
   at Microsoft.UI.Xaml.Application.Microsoft.UI.Xaml.IApplicationOverrides.OnLaunched(LaunchActivatedEventArgs args)
   at ABI.Microsoft.UI.Xaml.IApplicationOverrides.Do_Abi_OnLaunched_0(IntPtr thisPtr, IntPtr args)

集成步骤:

  • 添加H.NotifyIcon.WinUI NuGet依赖
  • 在App.xaml的<Application/>标签中添加xmlns:tb="using:H.NotifyIcon"命名空间
  • 将示例中TrayIconResources.xaml的XamlUICommand和tb:TaskbarIcon代码添加到App.xaml的ResourceDictionary(尝试过直接引用MergedDictionaries,问题依旧)
  • 在App.xaml.cs的OnLaunched方法中访问Resources["TrayIcon"]

核心现象:ResourceDictionary中的XamlUICommand可正常访问,仅TaskbarIcon资源触发错误;移除IconSource属性后错误仍存在,图标文件的生成操作和复制设置均正确。

解决方案

1. 避免在Application级ResourceDictionary中声明TaskbarIcon

TaskbarIcon依赖Win32托盘组件的UI上下文,Application级资源初始化时,窗口环境尚未完全就绪,导致COM交互失败。建议将TaskbarIcon的声明移至窗口级ResourceDictionary,或通过代码动态创建。

2. 代码动态创建TaskbarIcon(推荐)

在OnLaunched方法中动态实例化TaskbarIcon,确保窗口上下文就绪后再创建:

using H.NotifyIcon;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.ApplicationModel.Activation;

namespace Project
{
    public partial class App : Application
    {
        private TaskbarIcon _trayIcon;

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            // 初始化主窗口
            var mainWindow = new MainWindow();
            mainWindow.Activate();

            // 创建TaskbarIcon实例
            _trayIcon = new TaskbarIcon
            {
                Visibility = Visibility.Visible,
                ToolTipText = "ToolTip",
                ContextMenuMode = ContextMenuMode.SecondWindow,
                LeftClickCommand = Resources["ShowHideWindowCommand"] as ICommand,
                NoLeftClickDelay = true,
                IconSource = new BitmapIconSource { UriSource = new Uri("ms-appx:///Assets/app.ico") }
            };

            // 配置上下文菜单
            var flyout = new MenuFlyout();
            flyout.Items.Add(new MenuFlyoutItem { Command = Resources["ShowHideWindowCommand"] as ICommand });
            flyout.Items.Add(new MenuFlyoutSeparator());
            flyout.Items.Add(new MenuFlyoutItem { Command = Resources["ShowWindowViewCommand"] as ICommand });
            flyout.Items.Add(new MenuFlyoutItem { Command = Resources["ShowEventViewCommand"] as ICommand });
            flyout.Items.Add(new MenuFlyoutSeparator());
            flyout.Items.Add(new MenuFlyoutItem { Command = Resources["ExitApplicationCommand"] as ICommand });
            _trayIcon.ContextFlyout = flyout;
        }
    }
}

3. 无窗口项目的额外处理

如果是无窗口项目,需先初始化CoreWindow确保UI线程环境就绪:

using Windows.UI.Core;

protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
    if (CoreApplication.MainView == null)
    {
        CoreApplication.CreateNewView();
        await CoreApplication.MainView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            var window = CoreWindow.GetForCurrentThread();
            window.Activate();
        });
    }

    // 后续创建TaskbarIcon的代码同上
}

4. 更新H.NotifyIcon版本

确保使用最新稳定版的H.NotifyIcon.WinUI NuGet包,旧版本可能存在与.NET 8的兼容性问题。

原因分析

TaskbarIcon内部依赖Win32原生托盘组件,需要完整的UI窗口上下文才能完成COM对象初始化。而Application级ResourceDictionary在应用启动早期加载,此时窗口环境尚未完全建立,导致托盘组件初始化失败,抛出未指定的COM错误。XamlUICommand是纯逻辑对象,无UI上下文依赖,因此可以正常访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:56:10