【免费下载链接】AF-Media-Bar
Windows 10/11 桌面上的媒体控制与轻度美化软件。 Media control and minor beautification software for Windows 10/11 desktops.
AF Media Bar 是一款 Windows 10/11 任务栏媒体控制器,它从系统媒体会话(SMTC)读取正在播放的内容,把歌曲信息、歌词、播放控制和设备切换直接呈现到任务栏上。本文将带你拆解它如何用WPF + MVVM + Win32三层技术协作,完成一个「嵌入系统任务栏」的高难度桌面应用的分层设计,帮你快速读懂这套架构。
一、先认识它:一个「住在任务栏里」的媒体栏
与常见的悬浮播放器不同,AF Media Bar 的媒体栏不是普通窗口,而是嵌进 Windows 资源管理器(Explorer)任务栏的子窗口。这带来三个架构挑战:
- 🪟宿主是别人的窗口:媒体栏必须找到任务栏的 HWND,把自己设为其子窗口,还要做点击穿透,让任务栏其余部分照常可用;
- 📡数据来自系统通道:播放信息主要来自系统媒体会话(SMTC),部分播放器(如网易云)还需额外的进程内存读取通道;
- 🧵多窗口、多线程、长生命周期:托盘图标、歌词 WebView、频谱采样、后台剪枝都要在退出时按依赖顺序干净释放。
项目官方把目录、职责、线程和资源所有权完整写在 docs/architecture.md,建议配合本文一起读。
二、分层总览:五层结构各司其职
整个应用可以抽象成五层,依赖方向严格自上而下,绝不反向:
| 层 | 代表目录 | 职责 |
|---|---|---|
| 🖼️ 视图层 Views | src/AFMediaBar/Views/ | 窗口宿主:HWND、DPI、Z 序、显示/隐藏与状态转发 |
| 🧩 组件层 Components | src/AFMediaBar/Components/MediaBar/ | 媒体呈现:封面、元数据滚动、频谱、动画与输入意图 |
| 🧠 视图模型层 ViewModels | src/AFMediaBar/ViewModels/ | 可绑定状态、命令与异步协调 |
| ⚙️ 服务层 Services | src/AFMediaBar/Classes/Services/ | 按领域分目录的业务逻辑(Media、Lyrics、Audio、Taskbar…) |
| 📦 契约层 Classes | src/AFMediaBar/Classes/ | Models 数据模型、Abstractions 接口、Interop 原生互操作 |
几条关键的单向依赖规则(见 docs/architecture.md 的「依赖与平台宿主」一节):
- Service不依赖ViewModel、具体 View 或窗口是否存在;
- Model 与纯策略不执行I/O、Dispatcher 或 HWND 操作;
- ViewModel不引用具体 View、HWND 或
App.Services; - 宿主窗口负责 HWND/消息/DPI/Z 序,但不拥有业务算法。
这条边界让「任务栏窗口」「桌面悬浮窗」「设置窗口」可以共用同一套服务与视图模型。
三、组合根:App.xaml.cs 如何装配整个应用
应用入口 src/AFMediaBar/App.xaml.cs 是全项目唯一的组合根:它基于 .NET Generic Host 构建 DI 容器,注册全部服务、窗口和设置页面。
⚠️ 上面为运行演示图,此处仅作示意占位,实际文中仅引用一次,请忽略本行——正文排版以图片实际渲染为准。
启动流程的编排很有讲究,值得新手学习:
- 日志最先建立——之后设置读写、语言、宿主、托盘、更新的每一步都写入日志,出问题时整份目录即可上报;
- 加载「我的默认设置」快照——必须在宿主启动前,保证「恢复默认」点击即生效;
- 应用界面语言——先于窗口构建,避免第一帧短暂停留在另一种语言上;
- 处理待安装更新——「打开程序 → 安装进度 → 新版本启动」,比退出时安装更符合用户直觉;
- 最后启动后台剪枝——它要等媒体会话目录就绪才能判断「现在有没有在播」。
退出路径同样精心:App.OnExit是最终退出边界,先关闭菜单/Popup/窗口,再按依赖顺序停止 Hook、托盘、媒体来源与宿主,并有超时兜底,防止任何一步卡死整个退出。
四、Win32 互操作:媒体栏如何「住进」任务栏
这是全项目最有含金量的部分。核心实现在 src/AFMediaBar/Classes/Services/Taskbar/TaskbarDockService.cs,它把停靠算法收敛为四步:
- 找宿主:按显示器设备标识定位目标显示器上的任务栏窗口句柄;
- 变子窗口:修改窗口样式为
WS_CHILD,把媒体栏设为任务栏的子窗口; - 算位置:换算物理像素后调用
SetWindowPos落位; - 点击穿透:用
SetWindowRgn把输入区域裁剪到媒体栏本身,任务栏其余部分照旧可点。
所有 Win32 API 声明集中在 src/AFMediaBar/Classes/Interop/ 下的NativeMethods分部类中,按主题拆分(窗口、网络、电源、屏幕捕获),业务代码不直接散落 P/Invoke。
任务栏本身由 src/AFMediaBar/Views/Windows/TaskbarWindow.xaml.cs 承载:一个覆盖整个任务栏的透明子窗口,媒体栏通过 Canvas 放置并裁剪。它还要持续监听任务栏移动、隐藏、Explorer 重启等环境变化,并做恢复——相关策略(TaskbarRecoveryPolicy、TaskbarOccupancyRefreshPolicy等)都归在 src/AFMediaBar/Classes/Services/Taskbar/ 目录。
另外还有一个「模式切换器」BarRuntimeCoordinator:当用户在「任务栏模式」和「桌面悬浮模式」之间切换时,它串行地挂起旧宿主、激活新宿主,全部成功后才发布实际模式;失败则恢复原宿主。这种「先立后破 + 代际校验」是处理 UI 状态事务的好范例。
五、媒体数据流:从 SMTC 会话到 UI 快照
数据流遵循「服务生产快照 → 事件发布 → UI 消费」的单向模式:
播放器进程 ──SMTC/内存通道──▶ MediaSessionService ──MediaSnapshot──▶ TaskbarWindowViewModel ──绑定──▶ 媒体栏 UI关键角色:
- 🎯 MediaSessionService:协调会话目录、来源选择、快照构建,向 ViewModel 发布统一状态;
- 📸
MediaSnapshotBuilder:从选中的 SMTC 会话构建统一媒体快照,并异步补充歌词; - 🔌 可插拔来源扩展:IMediaSourceProvider 契约让酷狗、网易云等来源各自「认领」属于自己的会话,互不干扰。新增播放器适配器只需遵循 docs/media-adapters.md 的六步流程,无需改动通用管线。
这套设计呼应了 CONTEXT.md 中定义的领域术语:SMTC 通道(系统会话)与内存通道(进程读取)是同一个「媒体来源」下的两条信息通道,而不是两个来源。
六、MVVM 边界:ViewModel 与宿主如何分工
以任务栏媒体栏为例,三方分工非常清晰:
| 角色 | 文件 | 只做 |
|---|---|---|
| 窗口宿主 | TaskbarWindow.xaml.cs | HWND 生命周期、停靠、DPI、消息泵 |
| 视图模型 | TaskbarWindowViewModel.cs | 会话/播放控制状态、右键菜单命令、更新进度绑定 |
| 呈现控件 | TaskBarMediaControl.xaml | 封面、元数据、频谱的绘制与动画意图 |
ViewModel 用 CommunityToolkit.Mvvm 的[ObservableProperty]生成绑定属性,只表达状态和命令;一切涉及 HWND 的操作都被挡在窗口宿主一侧。这样同一套 ViewModel 逻辑可以复用于任务栏窗口、紧凑弹出面板和开发者工具窗口。
七、横向能力:设置契约、歌词与资源治理
- ⚙️设置:SettingsManager 是全局设置门面,负责变更通知与重置;文件持久化由独立的
SettingsPersistenceService承担。设置契约有专门工具校验(tools/settings-contracts.ps1),架构细节见 docs/settings-architecture.md。 - 🎤歌词:src/AFMediaBar/Classes/Services/Lyrics/ 按 Cache / Parsing / Presentation / Providers 四个子域组织,多个歌词来源按优先级链式尝试,并用 WebView2 渲染逐字滚动歌词。
- 🧹内存治理:休眠/息屏时
MemoryPruneCoordinator发布剪枝档位,各服务实现IMemoryPrunable自行回收资源——协调器只发通知,不碰别人的资源,这是长驻桌面程序控制内存的教科书式做法。 - ✅测试:tests/AFMediaBar.Layout.Tests/ 按领域(Hosting、Lyrics、Media、Settings…)组织回归测试,覆盖生命周期、呈现与策略逻辑。
八、新手读源码路线图 🗺️
建议按这个顺序通读,两小时即可建立全局观:
- docs/architecture.md——目录职责与所有权总表;
- src/AFMediaBar/App.xaml.cs——DI 注册即服务清单,启动/退出时序一目了然;
- TaskbarDockService.cs + NativeMethods.cs——理解 Win32 停靠的全部魔法;
- MediaSessionService.cs——媒体数据流主干;
- docs/media-adapters.md 与 docs/settings-architecture.md——扩展规范与设置架构。
一句话总结:AF Media Bar 用「组合根装配 → 服务生产快照 → 视图模型绑定 → 窗口宿主操作 HWND」的严格单向依赖,把 WPF 的声明式 UI 与 Win32 的窗口底层能力缝合在一起——这正是「WPF + MVVM + Win32」分层设计的精髓:每一层只对自己拥有的资源负责,依赖永远只指向下方。
【免费下载链接】AF-Media-Bar
Windows 10/11 桌面上的媒体控制与轻度美化软件。 Media control and minor beautification software for Windows 10/11 desktops.
相关推荐
低配PC能跑PS5游戏吗?AnyPS5硬件要求与Vulkan特性判断指南
低配PC能跑PS5游戏吗?AnyPS5硬件要求与Vulkan特性判断指南 想在 低配PC 上运行 PS5游戏 ,先别急着放弃。开源工具 AnyPS5 是一个自动
EarTrumpet 架构解析:基于 Windows 多媒体设备 API 的 WPF 音量控制应用设计
EarTrumpet 架构解析:基于 Windows 多媒体设备 API 的 WPF 音量控制应用设计 本文以 EarTrumpet 仓库的技术文档( EarT
桌面应用视频号、抖音、小红书视频下载?这个免费开源工具几步搞定
视频号、抖音、小红书视频下载?这个免费开源工具几步搞定 想收藏一个视频,翻遍点赞、转发、收藏,就是找不到"保存"按钮——视频下载这事,在很多平台上就是个死结。后
桌面应用网络音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考