Windows XP Tablet Ed.Windows VistaWindows 2003Visual Studio 2008XAML.NET 3.0设计/图形架构师高级Windows XP.NET 3.5初学者C# 3.0WPF中级开发Visual StudioWindows.NETC#
WPF/XAML 通知图标和任务栏(系统托盘)弹出窗口






4.90/5 (77投票s)
将 WPF 和 XAML 与 Windows Forms 的 NotifyIcon 控件集成,在鼠标悬停在 NotifyIcon 上时显示一个时尚、风格化的弹出窗口。
目录
引言
我想创建一个 WPF 应用程序,该应用程序“驻留”在 Windows 系统托盘中,并在鼠标移动到任务栏图标上方时显示一个淡入淡出的弹出窗口。此外,我希望用户体验流畅而顺滑。我曾看到过 Live Mesh 任务栏客户端,非常喜欢它的工作方式,并认为类似的东西非常适合我设想的应用程序。
我已分享此示例,以便为有类似需求的项目提供一个良好的开端。
背景
创建这个弹出窗口比预期的要困难,因为涉及大量琐碎的工作。外观和感觉并没有完全达到我想要的效果,窗口动画最初也非常笨拙。回想起来,我应该先在纸上或 Visio 中勾勒出设计和故事板,然后再开始动手。在使用 WPF 的设计器时,XAML 会迅速膨胀,而且真的需要小心如何组合 UI 元素和动画,以保持可维护性和灵活性。
还出现了一些意想不到的挑战,起初,实现流畅顺滑界面的总体目标似乎遥不可及。经过初步调查和一些探索性代码,我发现
- WPF 不支持原生的任务栏/系统托盘图标,需要利用 Windows Forms 的实现。
- 标准的
NotifyIcon 控件
不支持鼠标离开事件。 - 动画 WPF 窗口实现无缝淡入淡出并处理中断非常困难。
必备组件
- .NET Framework 3.0 或更高版本
- Windows XP、2003、Vista、2008
运行演示
从存档中解压演示,然后运行 WpfXamlPopup.exe。以下图表和相应的要点将引导您了解功能和用户界面。
![]() |
将鼠标悬停在任务栏图标上将导致弹出窗口显示。 |
![]() |
将鼠标移开任务栏图标后,会有一瞬间的延迟,然后弹出窗口会淡出。短暂的延迟允许鼠标无缝地移动到桌面和弹出窗口上。这为淡出被取消争取了时间,用户可以进一步与弹出窗口进行交互。 |
![]() |
“固定”按钮会将弹出窗口固定打开,而不管鼠标指针在桌面的哪个位置。 |
![]() |
“关闭”按钮会卸载弹出窗口和任务栏图标,并关闭应用程序。 |
![]() |
可用于应用程序的示例按钮 - 我想创建一个按钮似乎“弹出”到焦点中的效果。 |
![]() |
此单选按钮组演示了如何轻松更改任务栏图标。 |
Using the Code
首次打开解决方案文件(源代码)时,请生成解决方案,以便正确解析项目引用,并在设计器中查看弹出窗口。代码已进行了详细注释,因此我不会过多介绍,但我会解释总体架构和项目结构,以帮助您快速了解解决方案。
提供的解决方案 WPF XAML Notify Icon and Popup.sln
包含两个项目:
ExtendedWindowsControls
:一个类库,它公开 Windows Forms 的NofityIcon
控件,并用附加方法对其进行装饰,以满足本项目所需的交互。理想情况下,可以继承 Windows Forms 的NotifyIcon
类,但不幸的是,它是一个密封类,不允许继承。WpfXamlPopup
:主项目,如果您希望直接从 Visual Studio 运行应用程序,应将其设置为启动项目。该项目包含弹出窗口、淡入淡出动画和视觉样式资源。
我将逐一讨论代码文件,按下面的项目编号。
项目:ExtendedWindowsControls - 此项目提供了 Windows Forms 控件扩展的容器。 |
|
![]() |
ExtendedNotifyIcon.cs :
|
项目:WpfXamlPopup - 这是主项目,包含 WPF 弹出窗口。 |
|
![]() |
Images 文件夹包含项目中使用的所有图像。其中包括用于更改任务栏图标外观的各种彩色球体,以及用于固定和取消固定操作的按钮图像。 |
![]() |
App.xaml:包含对资源字典中存储的各种可重用 XAML 组件的引用。这些组件包括:SlickButtonRD.xaml、MainGridStyleRD.xaml 和 StealthButtonRD.xaml - 详见下文。 |
![]() |
HorizontalSeparatorRD.xaml:一个简单的用户控件,使用矩形的组合来生成带有“浮雕”效果的分隔线。 |
![]() |
MainGridStyleRD.xaml:一个资源字典,保存主网格的样式。主网格构成了弹出窗口的基础,并定义了
|
![]() |
MainNotifyWindow.xaml:这是主窗体的 XAML。由于有了资源字典文件和用户控件,此主窗口 XAML 简洁、优雅且易于理解。在 WPF 的这次简短探索中,我发现 XAML 文件很快就会变得笨重且难以管理。如果您使用 Blend,这会更加麻烦,因为它很容易生成大量无关的、未使用的/孤立的工件,清理起来会很费时。
|
![]() |
MainNotifyWindow.cs
|
![]() |
SlickButtonControl.cs:SlickToggleButton 控件通过添加附加属性来扩展标准的切换按钮。这些属性由 SlickButtonRD.xaml 中定义的样式使用。通过扩展 ToggleButton ,我消除了在需要对按钮进行细微更改(例如,具有不同的背景颜色和不同的圆角配置文件)时使用多个样式的需求。 |
![]() |
SlickButtonRD.xaml:此资源字典包含控件框中切换按钮的样式,并用于关闭和固定按钮。我不会详细介绍,但这些按钮很复杂,是通过一个包含 3 个边框元素的控件模板构建的,用于创建背景、边框样式,然后是用于显示按钮内容的 content target。暴露的 Triggers 处理 MouseOver 和 Checked 属性,以创建视觉上吸引人的按钮控件。 |
![]() |
StealthButtonRD.xaml:此资源字典包含弹出窗口底部按钮的样式。这些按钮看起来并不显眼,但当鼠标悬停在它们上方时,它们会“活起来”。这是通过使用“休眠/正常”样式和“鼠标悬停”样式来实现的。带有 ThicknessAnimation 和按钮边距操作的故事板提供了“弹出”效果。 |
关注点
- 总的来说,我对这个小应用程序的工作方式很满意。动画流畅,任务栏图标响应迅速,用户体验具有优质感。
- 将来,在开始 WPF 或 Silverlight 项目之前,我会在白板上勾勒概念。我发现尝试在画布上布局项目,然后对其进行移动和更改样式非常耗时、混乱且繁琐。我发现先在其他画布(或纸上)勾勒出概念,然后从中生成 WPF 设计要容易得多。
- WPF 在最大化窗口时占用内存可能非常高。即便如此,内存管理器在窗口隐藏或最小化时也能很好地释放资源。
- 一个具有平滑边缘和可靠动画的流畅 WPF 设计看起来很棒——但需要付出代价。我花在这个项目上的时间比预期的要长得多,而且我不禁想到,很多 WPF 项目会因为低估用户界面需求而延期。
- 将 Windows Forms NotifyIcon 与 WPF 集成非常简单且有效。
- 我发现 Blend 设计器在开始时确实帮助了我很多,但后来在处理更技术性的项目时却让我陷入困境,而且它还生成了多余的代码。我实际上是在 Blend 中开始的,然后在 Visual Studio 中重构并完成,因为 Blend 实在太混乱了,而且我觉得我无法很好地控制组件的分离以及 Blend 中更棘手的样式工作。
已知问题
- 窗口可见并使用时内存使用量可能很高——我还没有找到更好的管理方法。
- 有时窗口(固定打开时)会失去其最顶层位置,并被另一个窗口遮挡。我不确定这是我的问题还是 .NET Framework 的问题。如果您遇到相同的问题或以前见过,请告诉我。
历史
- V1.0 - 初始发布
- V1.1 - 任务栏集成将在 .NET 4 中发布,应该允许此解决方案摆脱其 WinForms 依赖。有关 WPF 4.0 功能的更多信息,请参阅演示文稿 http://mschannel9.vo.msecnd.net/o9/mix/09/pptx/t39f.pptx 或查看 MIX 的视频 http://videos.visitmix.com/MIX09/T39F。
- V1.2 (2010 年 8 月 4 日) - 我已测试将项目升级到 Visual Studio 2010 并以 .NET 4.0 框架为目标(您必须在项目属性中设置)。升级过程快速而简单,并且应用程序在 .NET 4 上仍能完美运行。太棒了!
- V1.3 (2015 年 11 月 4 日) - 我再次测试了将项目升级到 Visual Studio 2015 并以 .Net 4.6 框架为目标。升级过程快速而简单,并且应用程序在 .Net 4.6 上仍能完美运行。太棒了!
希望您喜欢这篇文章和示例。非常欢迎提出建议、问题和评论,也欢迎您对文章和代码评分。