在 WinUI 3(桌面) 里,系统托盘(右下角通知区域)不是官方内置功能,需要 自己用 Win32 API + NotifyIcon 来实现。好消息是:完全可行,而且是现在的主流做法。
WinUI 3 = UI 托盘 = Win32
做法:
System.Windows.Forms.NotifyIcon 创建托盘图标在 项目文件 .csproj 中加:
<ItemGroup>
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />
</ItemGroup>
然后在代码中可以用:
using System.Windows.Forms;
⚠️ 不会变成 WinForms 程序,只是借用托盘组件
TrayIconService.csusing System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.UI.Dispatching;
public class TrayIconService : IDisposable
{
private readonly NotifyIcon _notifyIcon;
private readonly DispatcherQueue _dispatcher;
public TrayIconService(DispatcherQueue dispatcher)
{
_dispatcher = dispatcher;
_notifyIcon = new NotifyIcon
{
Text = "我的 WinUI 程序",
Icon = new Icon("Assets/app.ico"), // 一定要是 .ico
Visible = true
};
var menu = new ContextMenuStrip();
menu.Items.Add("显示", null, (_, _) => ShowWindow());
menu.Items.Add("退出", null, (_, _) => ExitApp());
_notifyIcon.ContextMenuStrip = menu;
_notifyIcon.DoubleClick += (_, _) => ShowWindow();
}
private void ShowWindow()
{
_dispatcher.TryEnqueue(() =>
{
App.MainWindow.Show();
App.MainWindow.Activate();
});
}
private void ExitApp()
{
_notifyIcon.Visible = false;
Environment.Exit(0);
}
public void Dispose()
{
_notifyIcon.Dispose();
}
}
App.xaml.cs 保存 MainWindowpublic partial class App : Application
{
public static MainWindow MainWindow { get; private set; }
private TrayIconService _tray;
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new MainWindow();
MainWindow.Activate();
_tray = new TrayIconService(
DispatcherQueue.GetForCurrentThread()
);
}
}
在 MainWindow.xaml.cs:
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using WinRT.Interop;
public sealed partial class MainWindow : Window
{
private AppWindow _appWindow;
public MainWindow()
{
InitializeComponent();
var hwnd = WindowNative.GetWindowHandle(this);
_appWindow = AppWindow.GetFromWindowId(
Win32Interop.GetWindowIdFromWindow(hwnd)
);
_appWindow.Closing += AppWindow_Closing;
}
private void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
{
args.Cancel = true; // 阻止真正关闭
MainWindow.AppWindow.Hide(); // 隐藏到托盘
}
}
👉 这样:
如果你想 点最小化也进托盘:
_appWindow.Changed += (s, e) =>
{
if (e.DidPresenterChange &&
s.Presenter is OverlappedPresenter p &&
p.State == OverlappedPresenterState.Minimized)
{
this.Hide();
}
};
.ico一定要拦截 AppWindow.Closing
✔ WinUI 3 托盘常驻 ✔ 最小化到右下角 ✔ 双击恢复 ✔ 右键菜单 ✔ 完全原生 Windows 行为