|
本帖最后由 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;
- [StructLayout(LayoutKind.Sequential)]
- private struct NOTIFYICONDATA
- {
- public int cbSize;
- public IntPtr hWnd;
- public int uID;
- public int uFlags;
- public int uCallbackMessage;
- public IntPtr hIcon;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
- public string szTip;
- }
- [DllImport("shell32.dll", SetLastError = true)]
- private static extern bool Shell_NotifyIcon(int dwMessage, ref NOTIFYICONDATA lpData);
- [DllImport("user32.dll", SetLastError = true)]
- private static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
- [DllImport("user32.dll", SetLastError = true)]
- 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);
- }
- }
复制代码 |
|