WPF 中几种方式实现托盘图标功能
本帖最后由 shiy720 于 2025-3-5 14:24 编辑除了使用 `System.Windows.Forms` 的 `NotifyIcon` 控件外,WPF 中还可以通过以下几种方式实现托盘图标功能:
### 方法 1:使用 WPF 的 `Window` 和 `TaskbarIcon` 第三方库
`TaskbarIcon` 是一个流行的开源库(如 `Hardcodet.NotifyIcon.Wpf`),专门为 WPF 设计,提供了更现代化的托盘图标实现,避免了依赖 Windows Forms。
#### 实现步骤:
1. **安装 NuGet 包**:
在项目中安装 `Hardcodet.NotifyIcon.Wpf` 包:
Install-Package Hardcodet.NotifyIcon.Wpf
2. **在 XAML 中使用 `TaskbarIcon`**:
在 `MainWindow.xaml` 或 `App.xaml` 中添加 `TaskbarIcon` 控件:
<Window x:Class="WpfTrayIcon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
Title="MainWindow" Height="350" Width="525">
<Grid>
<!-- 其他内容 -->
</Grid>
<!-- 托盘图标 -->
<tb:TaskbarIcon x:Name="MyNotifyIcon"
IconSource="/icon.ico"
ToolTipText="My WPF Application">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Show" Click="OnShowClicked" />
<MenuItem Header="Exit" Click="OnExitClicked" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
</Window><Window x:Class="WpfTrayIcon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
Title="MainWindow" Height="350" Width="525">
<Grid>
<!-- 其他内容 -->
</Grid>
<!-- 托盘图标 -->
<tb:TaskbarIcon x:Name="MyNotifyIcon"
IconSource="/icon.ico"
ToolTipText="My WPF Application">
<tb:TaskbarIcon.ContextMenu>
<ContextMenu>
<MenuItem Header="Show" Click="OnShowClicked" />
<MenuItem Header="Exit" Click="OnExitClicked" />
</ContextMenu>
</tb:TaskbarIcon.ContextMenu>
</tb:TaskbarIcon>
</Window>
3. **在代码中处理事件**:
在 `MainWindow.xaml.cs` 中处理菜单项的点击事件:
private void OnShowClicked(object sender, RoutedEventArgs e)
{
this.Show();
this.WindowState = WindowState.Normal;
}
private void OnExitClicked(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
4. **隐藏窗口时显示托盘图标**:
在窗口关闭时隐藏窗口而不是退出应用程序:
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = true; // 取消关闭
this.Hide(); // 隐藏窗口
base.OnClosing(e);
}
5. **添加图标文件**:
确保项目中有一个图标文件(如 `icon.ico`),并将其“生成操作”设置为“资源”。
### 方法 2:使用 Windows API(P/Invoke)
如果不想依赖任何外部库,可以通过调用 Windows API 实现托盘图标功能。这种方法需要手动处理托盘图标的创建、更新和销毁。
#### 实现步骤:
1. **定义 Windows API 结构和方法**:
在项目中定义必要的 Windows API 结构和 P/Invoke 方法:
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public partial class MainWindow : Window
{
private const int WM_USER = 0x0400;
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_RBUTTONUP = 0x0205;
private const int NIM_ADD = 0x00000000;
private const int NIM_MODIFY = 0x00000001;
private const int NIM_DELETE = 0x00000002;
private const int NIF_MESSAGE = 0x00000001;
private const int NIF_ICON = 0x00000002;
private const int NIF_TIP = 0x00000004;
private struct NOTIFYICONDATA
{
public int cbSize;
public IntPtr hWnd;
public int uID;
public int uFlags;
public int uCallbackMessage;
public IntPtr hIcon;
public string szTip;
}
private static extern bool Shell_NotifyIcon(int dwMessage, ref NOTIFYICONDATA lpData);
private static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
private static extern bool DestroyIcon(IntPtr hIcon);
private NOTIFYICONDATA notifyIconData;
private IntPtr hIcon;
public MainWindow()
{
InitializeComponent();
InitializeTrayIcon();
}
private void InitializeTrayIcon()
{
notifyIconData = new NOTIFYICONDATA();
notifyIconData.cbSize = Marshal.SizeOf(notifyIconData);
notifyIconData.hWnd = new WindowInteropHelper(this).Handle;
notifyIconData.uID = 0;
notifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
notifyIconData.uCallbackMessage = WM_USER + 1;
hIcon = LoadIcon(IntPtr.Zero, new IntPtr(32512)); // 使用默认图标
notifyIconData.hIcon = hIcon;
notifyIconData.szTip = "My WPF Application";
Shell_NotifyIcon(NIM_ADD, ref notifyIconData);
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == notifyIconData.uCallbackMessage)
{
switch ((int)lParam)
{
case WM_LBUTTONDBLCLK:
ShowWindow();
break;
case WM_RBUTTONUP:
// 显示右键菜单
break;
}
}
return IntPtr.Zero;
}
private void ShowWindow()
{
this.Show();
this.WindowState = WindowState.Normal;
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
Shell_NotifyIcon(NIM_DELETE, ref notifyIconData);
DestroyIcon(hIcon);
base.OnClosing(e);
}
}
页:
[1]