前言&问题背景
Windows平台上很多需要持续后台运行的程序,都有显示任务栏图标的需求,主要来显示状态信息、提供功能菜单栏。但UWP或Windows App SDK并没有提供对应的API,相反可能是在有意的抑制此项功能,我有理由怀疑是微软的战略布局。
但很显然,这项功能目前并不能有其它完美的替代解决方案,所以需要借助其它手段调用Win32 API实现。确实如此,GitHub中H.NotifyIcon库就帮助我们在WPF和WinUI平台上实现了。我们只需使用其NuGet包即可显示自己的任务栏图标。
但请注意,UWP程序强调生命周期管理,在后台期间会自动挂起。在官方的文档中,UWP确实有“在后台无限期运行”的解决方案,但一经使用则不能发布到Microsoft Store。为了响应其设计理念、也因为作者确实此方面涉足不深,本篇文章不探讨UWP平台的任务栏图标功能或后台运行功能。
解决方案
在NuGet源中,找到H.NotifyIcon
包,根据你的需要选择H.NotifyIcon.WinUI
或H.NotifyIcon.Uno
等包并安装。
注意,根据项目实例和自述文件,可以有多种声明与使用方法:
- 直接全部在
MainWindow
内声明
<Window
...
xmlns:tb="using:H.NotifyIcon"
>
<Grid>
<Grid.Resources>
<MenuFlyout x:Key="TrayContextFlyout">
<MenuFlyoutItem Command="{StaticResource XamlUICommand类指令}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem Command="{StaticResource XamlUICommand类指令}" />
</MenuFlyout>
</Grid.Resources>
<tb:TaskbarIcon
x:Name="TrayIconView"
ToolTipText="悬停时显示的提示语文字,如ToolTip"
IconSource="图标文件路径,如/Images/TrayIcons/Logo.ico"
ContextMenu="ContextMenu资源,如{StaticResource TrayMenu}"
MenuActivation="显示菜单栏的行为,如LeftOrRightClick"
TrayPopup="弹出窗口资源,如{StaticResource TrayStatusPopup}"
PopupActivation="显示弹出窗口的行为,如DoubleClick"
LeftClickCommand="左键单击执行的命令,如{StaticResource Command}"
ContextMenuMode="SecondWindow"
NoLeftClickDelay="True"
/>
</Grid>
</Window>
- 定义一个
UserControl
,再在MainWindow
使用
<Window
...
xmlns:views="using:UserControl所在命名空间"
>
<Grid>
...
<views:TrayIconView x:Name="TrayIconView" />
</Grid>
</Window>
<UserControl ... >
<UserControl.Resources>
<MenuFlyout x:Key="TrayContextFlyout">
<MenuFlyoutItem Command="{StaticResource XamlUICommand类指令}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem Command="{StaticResource XamlUICommand类指令}" />
</MenuFlyout>
</UserControl.Resources>
<tb:TaskbarIcon
ToolTipText="悬停时显示的提示语文字,如ToolTip"
IconSource="图标文件路径,如/Images/TrayIcons/Logo.ico"
ContextMenu="ContextMenu资源,如{StaticResource TrayMenu}"
MenuActivation="显示菜单栏的行为,如LeftOrRightClick"
TrayPopup="弹出窗口资源,如{StaticResource TrayStatusPopup}"
PopupActivation="显示弹出窗口的行为,如DoubleClick"
LeftClickCommand="左键单击执行的命令,如{StaticResource Command}"
ContextMenuMode="SecondWindow"
NoLeftClickDelay="True"
/>
</UserControl>
个人更推荐第二种方法,这样不让主窗口文件显得臃肿,方便维护。
注意替换以上文字部分,要自行在Resources
部分定义XamlUICommand
指令并在MenuFlyoutItem
中使用。
注意:在退出(Window Closed
或自定义退出命令中)程序时,要调用TrayIconView.Dispose()
方法。
注意:在退出(Window Closed
或自定义退出命令中)程序时,要调用TrayIconView.Dispose()
方法。
注意:在退出(Window Closed
或自定义退出命令中)程序时,要调用TrayIconView.Dispose()
方法。
这里补充说明一下以上文字部分的注释:
-
XamlUICommand
类指令,直接定义在菜单栏中显示的图标、标签内容等的自定义命令,可在WinUI示例代码找到说明。 -
ContextMenuMode="SecondWindow"
指定了菜单栏显示模式。“SecondWindow”指创建新的窗口覆盖Win32菜单栏,以使用WinUI风格设计的菜单栏。
注意:作者在指定到本模式时,在Window代码中注册Activated等事件会产生运行时错误,因为H.NotifyIcon也会对UI元素事件进行注册,见issue #37。因此你需要将注册到这些事件的代码移动到App.xaml.cs
或删除本项属性,则会默认仅使用Win32风格菜单栏(不自动再创建窗口)。
至此,题目的问题已经得到解决。
本篇博客有待更新,H.NotifyIcon
提供了更多实用方法和属性,包括XAML生成托盘图标、以效率模式隐藏窗口到后台等,读者可以自行从文首的GitHub链接到仓库探索。
总结&反思
WinUI没有提供系统托盘图标的API,所以要调用H.NotifyIcon
这类库来实现。
我本人十分欣赏这个项目,它可以用窗口覆盖的形式,应用WinUI风格的菜单栏到托盘图标,看起来符合Fluent Design设计语言,而不是老式的Win32风格。文章来源:https://www.toymoban.com/news/detail-459744.html
非常感谢H.NotifyIcon
的作者,从本项目可以看见很多可以让项目更符合Windows 11语言的新奇点子,暂时介绍不完了。文章来源地址https://www.toymoban.com/news/detail-459744.html
到了这里,关于【WinUI 3】用H.NotifyIcon显示系统任务栏(托盘)图标,实现程序后台运行的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!