WPF应用最小化时显示通知框及类Chrome自定义通知实现问询
嘿,我之前做WPF项目时刚好遇到过一模一样的需求,给你两个亲测有效的解决方案,完美解决你说的问题:
方案一:改造Popup控件,让主窗口最小化时不消失
你之前用Popup时遇到的主窗口最小化弹窗消失的问题,本质是Popup默认依附于主窗口,主窗口隐藏它也跟着隐藏。我们可以通过Win32 API把Popup的父窗口改成桌面,这样它就脱离主窗口的控制了:
步骤1:在XAML中定义Popup
先写一个基础的Popup布局,自定义你需要的通知内容:
<Popup x:Name="NotificationPopup" StaysOpen="True" Placement="Absolute" Width="300" Height="100"> <Border Background="#FFFFFF" BorderBrush="#E5E7EB" BorderThickness="1" CornerRadius="4"> <StackPanel Margin="12"> <TextBlock FontWeight="SemiBold" Text="新通知" FontSize="14"/> <TextBlock Text="这是一条测试通知内容" FontSize="12" Margin="0,4,0,0" Foreground="#4B5563"/> </StackPanel> </Border> </Popup>
步骤2:后台代码修改Popup的父窗口
引入Win32 API,把Popup的父窗口设置为桌面,同时监听主窗口的状态变化来控制Popup显示:
using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; public partial class MainWindow : Window { [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] private static extern IntPtr GetDesktopWindow(); public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; StateChanged += MainWindow_StateChanged; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { // 获取Popup的句柄并修改父窗口为桌面 var hwndSource = PresentationSource.FromVisual(NotificationPopup.Child) as HwndSource; if (hwndSource != null) { SetParent(hwndSource.Handle, GetDesktopWindow()); } } private void MainWindow_StateChanged(object sender, EventArgs e) { if (WindowState == WindowState.Minimized) { // 设置Popup到屏幕右下角位置 var screenWidth = SystemParameters.PrimaryScreenWidth; var screenHeight = SystemParameters.PrimaryScreenHeight; NotificationPopup.HorizontalOffset = screenWidth - NotificationPopup.Width - 20; NotificationPopup.VerticalOffset = screenHeight - NotificationPopup.Height - 20; NotificationPopup.IsOpen = true; } // 主窗口恢复时可以选择关闭Popup,或者保留,根据你的需求调整 // else { NotificationPopup.IsOpen = false; } } }
注意事项
- 如果需要Popup始终在最上层,可以设置
Popup.TopMost = true - 记得处理Popup的关闭逻辑,比如点击弹窗后关闭,或者定时自动关闭
方案二:自定义无任务栏的通知窗口(类似Chrome风格)
如果你想要更灵活的弹窗样式(比如带动画、自定义交互),可以用自定义Window,但要去掉任务栏图标,同时避免抢焦点:
步骤1:创建通知窗口的XAML
新建一个NotificationWindow.xaml,设置窗口属性让它不在任务栏显示,并且支持透明和自定义样式:
<Window x:Class="YourAppName.NotificationWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="320" Height="120" ShowInTaskbar="False" WindowStyle="None" AllowsTransparency="True" ShowActivated="False" TopMost="False" Background="Transparent"> <!-- 自定义你的通知内容,这里模拟Chrome的通知样式 --> <Border Background="#FFFFFF" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4"> <Grid Margin="12"> <Grid.ColumnDefinitions> <ColumnDefinition Width="40"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Ellipse Fill="#4285F4" Width="32" Height="32"/> <StackPanel Grid.Column="1" Margin="8,0,0,0"> <TextBlock FontWeight="Bold" Text="Chrome风格通知" FontSize="14"/> <TextBlock Text="这是一条来自自定义窗口的通知" FontSize="12" Margin="0,4,0,0" Foreground="#666666"/> </StackPanel> </Grid> </Border> </Window>
步骤2:主窗口中控制通知窗口的显示
在主窗口的后台代码中,监听窗口状态变化,当主窗口最小化时显示通知:
using System; using System.Windows; public partial class MainWindow : Window { private NotificationWindow _notificationWindow; public MainWindow() { InitializeComponent(); StateChanged += MainWindow_StateChanged; } private void MainWindow_StateChanged(object sender, EventArgs e) { if (WindowState == WindowState.Minimized) { ShowCustomNotification(); } } private void ShowCustomNotification() { // 避免重复创建窗口 if (_notificationWindow == null || !_notificationWindow.IsVisible) { _notificationWindow = new NotificationWindow(); // 设置窗口到屏幕右下角 var screenWidth = SystemParameters.PrimaryScreenWidth; var screenHeight = SystemParameters.PrimaryScreenHeight; _notificationWindow.Left = screenWidth - _notificationWindow.Width - 20; _notificationWindow.Top = screenHeight - _notificationWindow.Height - 20; _notificationWindow.Show(); // 可选:添加自动关闭逻辑,比如3秒后关闭 var timer = new System.Windows.Threading.DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(3); timer.Tick += (s, args) => { _notificationWindow.Close(); timer.Stop(); }; timer.Start(); } } }
注意事项
ShowActivated="False"可以让弹窗不会激活,不会抢走主窗口的焦点- 如果需要弹窗动画,可以给Window添加
Window.Triggers实现淡入淡出效果 - 多个通知时可以做堆叠布局,比如新通知在旧通知上方
内容的提问来源于stack exchange,提问作者soliloquyy
相关产品推荐
相关产品推荐

