
桌面应用【免费下载链接】SoundSwitchC# application to switch default playing device. Download: https://soundswitch.aaflalo.me/项目地址https://gitcode.com/gh_mirrors/so/SoundSwitch点击查看免费下载SoundSwitch 是一款用于切换 Windows 默认音频播放/录制设备的 C# 桌面应用。本文聚焦其SoundSwitch/Model领域由 Model 领域指南 定义系统讲解该层如何作为「框架代码与 UI 之间的状态与事件边界」运转从组合接口设计、partial class 拆分、事件 DTO 语义到热键注册、设置持久化与验证流程。读完本文你将掌握 SoundSwitch 模型层的职责划分、新增一项设置时必须接线的四个环节以及如何在修改模型代码后正确验证。Model 领域涵盖的范围按 Model/AGENTS.md 的定义SoundSwitch/Model领域负责以下四类构件构件代表性文件职责应用模型AppModel.cs 及多个AppModel.*.cs分部类组合设备服务、通知设置、应用设置与基础设施应用事件Events.cs、DeviceChangedEvent.cs以事件 DTO 向 UI 与框架层广播状态变化接口契约IAppModel.cs 及其聚焦子接口定义模型对外暴露的稳定属性与能力热键与应用上下文HotKeyAction.cs、SoundSwitchApplicationContext.cs热键动作枚举、应用启动装配与进程内 IPC 消息分发其核心边界思想是框架层音频枚举、设备切换、通知、托盘只负责怎么做模型层负责何时做什么、状态如何变化、如何持久化UI 层只负责展示与触发。三者通过模型暴露的事件与稳定属性解耦。三个核心职责状态边界、事件暴露、持久化协调AGENTS.md 明确了模型层的三条职责逐条对照源码说明其落地方式。1. 作为框架代码与 UI 之间的状态与事件边界模型层是唯一被 UI 直接持有的状态入口。例如 AppModel.cs 通过单例Instance暴露给整个应用public static IAppModel Instance { get; } new AppModel();UI 组件如托盘菜单、设置窗体只与IAppModel.Instance交互而音频设备枚举与切换则委托给SoundSwitch.Audio.Manager、DeviceCyclerManager、MicrophoneMuteToggler等框架组件。从 AppModel.cs 的构造函数可见模型在内部组装这些依赖UI 无须感知其实现细节private AppModel() { _notificationManager new NotificationManager(this, this, this); _deviceCyclerManager new DeviceCyclerManager(); _selectedDevices null; _microphoneMuteToggler new MicrophoneMuteToggler(AudioSwitcher.Instance); _updateScheduler new LimitedConcurrencyLevelTaskScheduler(1); }2. 通过事件与稳定属性暴露状态变化模型不要求 UI 轮询状态而是通过事件主动通知。例如切换默认设备成功后触发DefaultDeviceChanged设备列表变更后触发SelectedDeviceChanged见 AppModel.DeviceService.cs。UI 订阅这些事件刷新界面而模型自身对事件如何被消费一无所知从而保持单向依赖。3. 协调设置持久化但不嵌入表单逻辑所有设置属性的 setter 都遵循同一模式写配置 → 保存 → 广播事件。以 AppModel.NotificationSettings.cs 中的SwitchDeviceNotification为例public NotificationType SwitchDeviceNotification { get AppConfigs.Configuration.SwitchDeviceNotification; set { var previousSwitchDeviceNotification AppConfigs.Configuration.SwitchDeviceNotification; var previousSwitchProfileNotification AppConfigs.Configuration.SwitchProfileNotification; var previousMicrophoneMuteNotification AppConfigs.Configuration.MicrophoneMuteNotification; AppConfigs.Configuration.SwitchDeviceNotification value; if (!AppConfigs.Configuration.NotificationAdvancedMode) { AppConfigs.Configuration.SwitchProfileNotification value; AppConfigs.Configuration.MicrophoneMuteNotification value; } AppConfigs.Configuration.Save(); NotificationSettingsChanged?.Invoke(this, new NotificationSettingsUpdatedEvent(previousSwitchDeviceNotification, AppConfigs.Configuration.SwitchDeviceNotification, previousSwitchProfileNotification, AppConfigs.Configuration.SwitchProfileNotification, previousMicrophoneMuteNotification, AppConfigs.Configuration.MicrophoneMuteNotification)); } }设置窗体Settings.cs只需绑定这些属性并订阅NotificationSettingsChanged等事件即可保存、校验、级联逻辑全部收敛在模型内部。这正是不嵌入表单逻辑的含义模型是配置层AppConfigs与 UI 之间的唯一代理。组合接口 分部类IAppModel 与 AppModel 的对齐设计AGENTS.md 特别强调保持IAppModel与AppModel对齐。二者的对齐方式非常清晰接口侧组合而非巨型接口IAppModel.cs 只做一件事——把四个聚焦子接口组合起来public interface IAppModel : IDeviceService, INotificationSettings, IAppSettings, IAppInfrastructure, IDisposable { }四个子接口各自负责一个关注点IDeviceService.cs设备选择、默认设备切换、麦克风静音控制INotificationSettings.cs通知类型、横幅Banner位置/时长/透明度、自定义提示音、并发通知数量IAppSettings.cs开机自启、语言、更新通道、热键组合、遥测开关IAppInfrastructure.cs托盘图标、设备监听器、Profile 管理、App Sound Lock 管理、初始化入口。这种组合接口模式让调用方既可以通过IAppModel一次性访问全部能力也可以按需依赖某个子接口例如只关心设备服务的消费者仅依赖IDeviceService同时保持接口声明内聚。实现侧partial class 按关注点拆分AppModel.cs 声明为public partial class AppModel : IAppModel各关注点分散在独立分部类文件中与子接口一一对应分部类文件对应接口核心内容AppModel.csIAppInfrastructure生命周期InitializeMain/Dispose、单例、系统唤醒恢复处理AppModel.DeviceService.csIDeviceService选中设备集合、播放/录制设备枚举、切换与静音操作AppModel.NotificationSettings.csINotificationSettings全部通知与横幅设置属性AppModel.AppSettings.csIAppSettings应用级设置、热键注册与更新检查这一组织方式使得接口按关注点拆分、实现按关注点拆文件两者天然对齐——新增一个设置时接口声明与分部类实现的位置都能被快速定位。事件系统序列化无关、逻辑最小的事件 DTOAGENTS.md 要求事件 DTO 保持最小逻辑、与序列化无关。事件定义集中在 Events.cs全部继承EventArgs只携带「变更前/变更后」的数据快照不做任何处理。典型如设备默认角色变化事件 Events.cspublic class DeviceDefaultChangedEvent(DeviceFullInfo device, ERole role) { public string DeviceId Device.Id; public ERole Role { get; } role; public DeviceFullInfo Device { get; } device; }以及横幅设置变更事件BannerDataChangedEventEvents.cs它一次性携带 8 组 prev/new 快照横幅位置、显示时长、透明度、显示内容、静音/取消静音横幅。消费者如BannerManager只读这些属性渲染 UI事件 DTO 本身不含任何业务方法也不依赖具体序列化框架因此可以在 UI 线程与后台线程之间安全传递。变更规则新增设置的「四要素接线」AGENTS.md 给出了最关键的工程约束新增设置时必须同时接通四个环节——模型属性、持久化、迁移、运行时消费方。以真实存在的设置项逐一映射环节落点示例模型属性分部类属性 setter/getterSwitchForegroundProgramAppModel.AppSettings.cs持久化AppConfigs.Configuration对应字段 Save()见 AppConfigs.cs迁移MigratedFields标记 AppSoundRuleMigrator等迁移逻辑见 AppSoundRuleMigrator.cs 与 AppModel.cs 中的SwitchForegroundProgram_cleanup迁移分支运行时消费方事件订阅者、托盘菜单、热键处理器HandleHotkeyPress消费三个热键配置AppModel.AppSettings.cs值得注意的是 AppModel.cs 展示了一个完整的迁移范例当检测到旧的SwitchForegroundProgram_force_off迁移标记存在且用户已关闭该功能时模型会执行清理重置进程级设备配置并追加SwitchForegroundProgram_cleanup标记最后统一Save()。这验证了设置变更必须验证迁移路径的规则。热键的接线范例热键是「运行时消费方」最典型的一环。设置侧由SetHotkeyCombination统一处理AppModel.AppSettings.cs先注销旧组合、注册新组合再按HotKeyActionPlayback / Recording / Mute见 HotKeyAction.cs写入对应配置并保存。运行时侧HandleHotkeyPress根据命中的热键分派到CycleActiveDevice或ToggleMicrophoneMute并记录遥测。启动时若某个热键注册失败如被其他程序占用模型会自动禁用该热键并保存配置AppModel.cs保证应用不会因注册失败而崩溃。应用上下文模型与生命周期、IPC 的衔接点SoundSwitchApplicationContext.cs 是模型进入运行时的装配点继承 WinForms 的ApplicationContext负责初始化基础设施设置横幅管理器、麦克风静音横幅、快捷菜单创建CachedAudioDeviceLister并刷新设备注册MMNotificationClient启动模型调用AppModel.Instance.InitializeMain(deviceActiveLister, Program.SkipUpdate)见 AppModel.cs内部完成热键注册、通知管理器初始化、Profile 管理器与 App Sound Lock 管理器启动、更新检查器装配注册 IPC 消息处理器通过NamedPipe.RegisterMessageHandler处理来自 CLI/其他实例的请求包括麦克风状态查询与静音设置、打开设置、触发 Profile、切换设备、查询活动设备与可切换设备列表等首次运行引导若FirstRun为真自动弹出设置窗口。模型在这里充当 IPC 请求与实际操作的桥接层SoundSwitchApplicationContext收到TriggerSwitchRequest后调用AppModel.Instance.CycleActiveDevice(...)收到MuteRequest后调用AppModel.Instance.SetMicrophoneMuteState(...)。这也解释了为何模型必须提供稳定属性——IPC 的响应数据如设备名NameClean、活动 Profile 名均来自模型暴露的稳定查询接口。验证构建与设置变更的回归检查AGENTS.md 的 Validation 部分要求两条验证路径构建整个解决方案在仓库根目录执行dotnet build解决方案文件为 SoundSwitch.sln依赖版本由 Directory.Build.props 与 Directory.Packages.props 统一管理。模型层改动若破坏接口对齐编译期即可暴露。针对设置变更的专项验证改动任一设置项后至少验证三条路径——初始化读取首次启动时SelectedDevices从配置懒加载见 AppModel.DeviceService.cs、保存行为setter 内Save()被触发、迁移路径MigratedFields标记与迁移分支按旧配置组合正确执行。仓库中的测试套件SoundSwitch.Tests覆盖了模型相关行为例如 AppSoundRuleMigrationTests.cs 验证设置迁移逻辑、SettingsFormTests.cs 验证设置界面与模型的交互可作为修改模型后的回归参考。小结SoundSwitch 的Model领域是一个典型的状态与事件边界层组合接口定义契约、分部类按关注点实现、事件 DTO 只携带数据快照、所有设置走写配置→保存→广播事件的统一通道。对贡献者而言遵循 AGENTS.md 的规则意味着新增功能优先问状态应该由谁持有、变化如何广播、持久化与迁移在哪完成而这三问的答案都能在AppModel的分部类与Events.cs中直接落地验证。赞分享桌面应用【免费下载链接】SoundSwitchC# application to switch default playing device. Download: https://soundswitch.aaflalo.me/项目地址https://gitcode.com/gh_mirrors/so/SoundSwitch点击查看免费下载相关推荐JavaScript状态机生命周期事件全面解析JavaScript状态机生命周期事件全面解析 引言为什么需要状态机生命周期事件 在现代前端开发中状态管理State Management是构建复杂应开发工具EmDash Bot 状态机架构issue 生命周期与 Agent 运行生命周期的完整设计解析EmDash Bot 状态机架构issue 生命周期与 Agent 运行生命周期的完整设计解析 本篇技术指南以 BOT_STATE_MACHINE.md htCMS后端前端插件系统fetchbot最佳实践大型网站数据采集项目的架构设计与代码组织fetchbot最佳实践大型网站数据采集项目的架构设计与代码组织 fetchbot是一个简单灵活的网络爬虫遵循robots.txt协议和爬取延迟策略为大型后端上一篇深入解析 Rust 编译错误 E0690repr(transparent) 结构体不得拥有多个非零大小字段下一篇动态数据源健康检查PoolMetrics监控完整实现指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考