纯原生 Windows 闹钟工具V1.2
# 闹钟 · 项目说明- 当前版本:v1.2.0
- 最后更新:2026-11-03
- 程序形态:Windows 原生桌面应用(C# / WPF / .NET 10)
- 项目目录:`D:\Project\LobsterAI\闹钟软件`
---
## 软件图片
## 一、项目概览
一个纯原生 Windows 闹钟工具,不依赖 Electron、浏览器内核或第三方 UI 框架。核心目标是把「设闹钟 → 到点叫醒 → 关掉继续睡或起床」这条链路做得稳定、安静、不打扰。
交付形态:
1. 精简版 `dist\AlarmClock.exe`:约 286 KB,框架依赖单文件,需要 .NET 10 Desktop Runtime。
2. 自包含版 `dist\standalone\AlarmClock.exe`:约 66.6 MiB,内含运行时,双击即用。
3. 源码:`versions\vX.Y.Z\src\AlarmClock`,每个版本一份完整副本。
---
## 二、开发架构
### 2.1 技术选型
1. 语言与框架:C# 14 / WPF / .NET 10(`net10.0-windows`)。
2. UI:XAML + 自定义 ControlTemplate,无第三方控件库。
3. 音频:WPF `MediaPlayer`(支持 wav/mp3/wma 等,音量可调、可循环)。
4. 托盘:`System.Windows.Forms.NotifyIcon`(WPF 无原生托盘,与 WinForms 混用)。
5. 存储:`System.Text.Json`,本地 JSON 文件。
6. 系统集成:`Microsoft.Win32.Registry`(开机自启)、`RegisterHotKey`(全局快捷键)、`Mutex`(单实例)。
### 2.2 目录结构(v1.2.0)
```
闹钟软件/
├─ README.md 快速开始
├─ CHANGELOG.md 版本更新记录
├─ 项目说明.md 本文件
├─ dist/
│├─ AlarmClock.exe 精简版(框架依赖)
│└─ standalone/
│ └─ AlarmClock.exe 自包含版
└─ versions/
├─ v1.0.0/ 首发版本(完整副本)
├─ v1.1.0/ 试听 + 体积优化
├─ v1.1.1/ 修复全球化崩溃
└─ v1.2.0/ 当前版本:铃声库
├─ VERSION.md
├─ tools/make-icon.ps1
└─ src/AlarmClock/
├─ AlarmClock.csproj
├─ app.manifest
├─ App.xaml / App.xaml.cs
├─ MainWindow.xaml / MainWindow.xaml.cs
├─ RingingWindow.xaml / RingingWindow.xaml.cs
├─ icon.ico
├─ Models/
│├─ Alarm.cs
│├─ AppSettings.cs
│└─ RingRequest.cs
├─ Services/
│├─ AlarmMath.cs
│├─ AlarmScheduler.cs
│├─ SoundService.cs
│├─ StorageService.cs
│├─ AutoStartService.cs
│├─ ThemeService.cs
│└─ TrayService.cs
└─ Themes/
├─ Dark.xaml
├─ Light.xaml
└─ Controls.xaml
```
### 2.3 分层与职责
| 文件 | 行数 | 职责 |
| ------------------------------ | ---- | ---------------------------------------------------------- |
| `Models/Alarm.cs` | 195| 闹钟实体,INotifyPropertyChanged,时间/重复/状态等计算属性 |
| `Models/AppSettings.cs` | 10 | 全局设置(主题、自启、默认稍后、暂停、铃声库) |
| `Models/RingRequest.cs` | 14 | 一次响铃请求,连接调度器与响铃窗口 |
| `Services/AlarmMath.cs` | 48 | 重复规则匹配、下次响铃时间计算、一次性闹钟日期 |
| `Services/AlarmScheduler.cs` | 88 | 1 秒轮询,触发判定、稍后提醒、补提醒 |
| `Services/SoundService.cs` | 276| 内置铃声合成、播放/循环/渐强、试听、随机库抽取 |
| `Services/StorageService.cs` | 95 | alarms.json / settings.json 读写、备份、导入导出 |
| `Services/AutoStartService.cs` | 46 | HKCU Run 注册表读写 |
| `Services/ThemeService.cs` | 40 | 主题字典替换、系统深浅色判断 |
| `Services/TrayService.cs` | 72 | 托盘图标、右键菜单、气泡提示 |
| `App.xaml.cs` | 82 | 启动装配、单实例、全局异常、退出清理 |
| `MainWindow.xaml.cs` | 955| 主界面、编辑抽屉、计时器、设置、与调度器接线 |
| `RingingWindow.xaml.cs` | 77 | 全屏响铃窗口、快捷键、结果返回 |
| `Themes/Controls.xaml` | 410| 全部控件样式(按钮、开关、标签、滑块、滚动条等) |
设计取向:不使用 MVVM 框架,采用「实体实现 INotifyPropertyChanged + 代码后置 + 服务类」的轻量结构。原因是这个规模下 MVVM 的抽象成本高于收益,而实体通知足以支撑数据绑定。
### 2.4 关键运行流程
**启动流程**
1. `Mutex` 检查单实例,重复启动直接提示并退出。
2. 读取 `settings.json` 与 `alarms.json`(损坏时备份为 `.bak` 并回退空数据)。
3. 应用主题字典;创建 `SoundService`,首次运行合成 3 个内置 WAV。
4. 创建主窗口:绑定闹钟集合与排序视图,初始化调度器、时钟、托盘、全局快捷键。
5. `Loaded` 后启动 1 秒时钟与调度器;若带 `--tray` 参数或设置为静默启动,则直接隐藏到托盘。
**调度循环**
1. 每 1 秒执行一次 `Tick`,全部在 UI 线程完成(数据量小,无需并发)。
2. 若闹钟处于「稍后提醒」,优先检查 `SnoozeUntil`,到点重新入队。
3. 否则检查 `NextRing`:为空则按重复规则计算;已到点则触发。
4. 触发后:一次性闹钟自动禁用;重复闹钟从「当前时间 + 30 秒」重新计算下一次,避免同一分钟重复触发。
5. 实际触发时间比预定时间晚于 90 秒时标记为「补提醒」,用于休眠/关机恢复后的场景。
**响铃流程**
1. 调度器触发 `Due` 事件,主窗口把请求放入队列(支持多个闹钟同时到点,逐个显示)。
2. 创建全屏置顶 `RingingWindow`,显示时间、标签、补提醒标记。
3. `SoundService.PlayLoop` 播放:渐强开启时约 5 秒从 3% 音量升到目标音量,播放结束自动循环。
4. 用户点「停止」或按 Esc 关闭;点「稍后提醒」或按空格则记录 `SnoozeUntil`。
5. 窗口关闭时立即停止声音,队列中还有请求就继续显示下一个。
**试听流程**
1. 编辑面板点「▶ 试听」,按当前选中铃声播放,按钮变为「■ 停止」。
2. 12 秒后自动停止并复位按钮;再次点击可提前停止。
3. 试听与响铃共用同一个 `MediaPlayer`,真正响铃会抢占试听。
4. 试听中拖动音量滑块会实时改变播放音量。
**随机铃声库**
1. 设置页选择文件夹,路径保存到 `settings.json` 的 `RingLibraryFolder`。
2. 闹钟铃声选「随机库」时,`SoundPath` 存为标签 `folder:random`。
3. 响铃前解析:扫描文件夹第一层,按扩展名过滤出音频文件,随机抽一首,并排除上一首避免连播。
4. 库为空或路径不存在时回退内置「晨光」,不会出现静音闹钟。
**主题切换**
1. 深色/浅色是两个同键名的 `ResourceDictionary`,切换时整体替换 `MergedDictionaries`。
2. 所有样式使用 `DynamicResource` 引用颜色,替换后立即生效。
3. 「跟随系统」读取 `HKCU\...\Themes\Personalize\AppsUseLightTheme`,仅在启动时判断。
**系统集成**
1. 开机自启写入 `HKCU\Software\Microsoft\Windows\CurrentVersion\Run`,值为 `"exe路径" --tray`。
2. 全局快捷键 `Ctrl+Alt+A` 通过 `RegisterHotKey` 注册,`WM_HOTKEY` 时呼出主窗口并打开新建抽屉。
3. 关闭主窗口不退出,隐藏到托盘;托盘双击打开,右键可暂停全部或退出。
### 2.5 数据模型
**Alarm 字段**
| 字段 | 类型 | 说明 |
| ----------------- | ----------- | ------------------------------------------- |
| `Id` | string | GUID,无短横线 |
| `Hour` / `Minute` | int | 24 小时制 |
| `Label` | string | 名称,空值显示为「闹钟」 |
| `Repeat` | enum | Once / Daily / Weekdays / Weekends / Custom |
| `Days` | DayOfWeek[] | 自定义星期时使用 |
| `Enabled` | bool | 启停 |
| `AntiSnooze` | bool | 防贪睡,响铃时不显示稍后按钮 |
| `SnoozeMinutes` | int | 5 / 10 / 15 / 20 |
| `SoundPath` | string | `builtin:晨光`、`folder:random` 或绝对路径|
| `Volume` | double | 0.05 – 1.0 |
| `FadeIn` | bool | 渐强 |
| `OnceDate` | DateTime? | 一次性闹钟的日期 |
| `NextRing` | DateTime? | 下次响铃(持久化,用于补提醒) |
| `SnoozeUntil` | DateTime? | 稍后提醒的到点时间 |
**AppSettings 字段**
| 字段 | 默认| 说明 |
| ---------------------- | ----- | ---------------------- |
| `Theme` | Dark| Dark / Light / System|
| `AutoStart` | false | 开机自启 |
| `DefaultSnoozeMinutes` | 5 | 新建闹钟的默认稍后时长 |
| `StartMinimized` | false | 启动即隐藏到托盘 |
| `PausedAll` | false | 全部暂停 |
| `RingLibraryFolder` | 空 | 铃声库文件夹绝对路径 |
### 2.6 线程与计时
1. 所有界面、调度、存储操作都在 WPF UI 线程,避免跨线程访问 UI。
2. 计时全部使用 `DispatcherTimer`:调度 1 秒、倒计时 200 毫秒、秒表 50 毫秒、渐强 90 毫秒、试听 12 秒。
3. `MediaPlayer` 在 UI 线程创建;响铃与试听互斥,切换时先 `Stop` 再 `Open`。
4. 无自建后台线程,进程常驻但空闲时 CPU 占用极低(每秒一次轻量遍历)。
### 2.7 界面结构
1. 左侧 84px 导航栏:闹钟 / 计时器 / 设置。
2. 顶部:当前时间(44px)、日期、下一个闹钟卡片。
3. 闹钟页:卡片列表(时间、名称、重复、下次时间、开关),空状态引导。
4. 编辑抽屉:右侧 464px 滑出面板,时间步进、名称、重复、铃声、音量、渐强、防贪睡、稍后提醒。
5. 计时器页:倒计时(预设 3×2 网格 + 自定义分钟)与秒表(计次列表)。
6. 设置页:外观、行为、铃声库、数据、关于。
7. 响铃窗口:无边框全屏、置顶、脉冲光环、超大时间、稍后/停止按钮。
---
## 三、功能清单
**闹钟**
1. 新建、编辑、删除、启停,列表按时间自动排序。
2. 重复规则:仅一次、每天、工作日、周末、自定义星期。
3. 跨天时间:任意 00:00–23:59。
4. 一次性闹钟响后自动关闭。
5. 错过补提醒:休眠、睡眠或关机后恢复,补一次提醒并标记。
**铃声**
1. 内置 3 种合成铃声:晨光、经典、脉冲(首次运行生成 WAV)。
2. 自定义单个音频文件(wav/mp3/wma/m4a 等)。
3. 铃声库文件夹 + 随机抽取,不连续重复。
4. 试听:循环播放、手动停止、12 秒自动停止。
5. 音量 5%–100%,可选渐强(约 5 秒)。
6. 空库自动回退内置铃声。
**提醒行为**
1. 全屏置顶响铃窗口,支持多闹钟排队。
2. 稍后提醒 5/10/15/20 分钟。
3. 防贪睡:响铃后只能手动停止。
4. 全部暂停:到点不响,恢复后按原规则继续。
**计时工具**
1. 倒计时:5/10/15/25/45/60 分钟预设,支持 1–600 分钟自定义,进度条显示。
2. 秒表:开始/暂停/继续、计次、重置,计次列表倒序。
**系统集成**
1. 托盘常驻,关闭窗口不退出。
2. 托盘菜单:打开、暂停全部/恢复全部、退出。
3. 托盘悬停显示下一个闹钟时间。
4. 开机自启(当前用户,静默启动)。
5. 全局快捷键 `Ctrl+Alt+A`。
6. 单实例保护。
7. 深色 / 浅色 / 跟随系统主题。
8. JSON 导入导出、打开数据目录。
---
## 四、快捷键
| 快捷键 | 场景 | 作用 |
| ------------ | -------------- | ------------------------ |
| `Ctrl+Alt+A` | 全局 | 呼出主窗口并新建闹钟 |
| `↑` / `↓` | 编辑面板时间框 | 小时/分钟加减 1 |
| 鼠标滚轮 | 编辑面板时间框 | 小时/分钟加减 1 |
| `Tab` | 编辑面板 | 从小时跳到分钟 |
| `Ctrl+S` | 编辑面板 | 保存 |
| `Esc` | 编辑面板 | 取消并关闭 |
| `空格` | 响铃窗口 | 稍后提醒(防贪睡时无效) |
| `Esc` | 响铃窗口 | 停止响铃 |
---
## 五、数据位置
| 内容 | 路径 |
| -------- | ------------------------------------------------------------ |
| 闹钟数据 | `%APPDATA%\AlarmClock\alarms.json` |
| 全局设置 | `%APPDATA%\AlarmClock\settings.json` |
| 内置铃声 | `%APPDATA%\AlarmClock\sounds\晨光.wav`、`经典.wav`、`脉冲.wav` |
| 异常日志 | `%APPDATA%\AlarmClock\error.log` |
| 损坏备份 | `alarms.json.bak`(解析失败时生成) |
`alarms.json` 是数组,每个元素对应一个闹钟;枚举以字符串存储,便于阅读和手工修复。`settings.json` 是单个对象。两者都使用缩进格式,可直接编辑,但建议改完再启动程序以免被覆盖。
---
## 六、开发与构建
### 6.1 环境要求
1. 开发:.NET 10 SDK(含 Windows Desktop 工作负载)。
2. 运行精简版:.NET 10 Desktop Runtime。
3. 运行自包含版:无额外依赖。
4. 系统:64 位 Windows 10 / 11。
### 6.2 构建
```powershell
cd versions\v1.2.0\src\AlarmClock
dotnet build -c Release
```
### 6.3 发布精简版
```powershell
dotnet publish -c Release -r win-x64 --self-contained false `
-p:PublishSingleFile=true -o ..\..\..\..\dist
```
注意:框架依赖的单文件发布不能开启 `EnableCompressionInSingleFile`,否则会报 `NETSDK1176`。
### 6.4 发布自包含版
```powershell
dotnet publish -c Release -r win-x64 --self-contained true `
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true `
-p:EnableCompressionInSingleFile=true -o ..\..\..\..\dist\standalone
```
### 6.5 图标
```powershell
powershell -ExecutionPolicy Bypass -File versions\v1.2.0\tools\make-icon.ps1
```
脚本用 `System.Drawing` 画一个圆角珊瑚色方块 + 白色表针,输出多尺寸 PNG 压缩的 `icon.ico`(256/64/48/32/16)。`csproj` 通过 `<ApplicationIcon>` 引用,构建时嵌入 exe。
### 6.6 版本化约定
1. 每次改动都从最新版本目录复制出新的 `versions/vX.Y.Z`,不在旧版本上覆盖。
2. 新版本附 `VERSION.md`,说明改动、验证方式与已知限制。
3. 根目录 `CHANGELOG.md` 追加条目,最新版本在最上面。
4. 发布产物统一输出到 `dist`(精简版)与 `dist\standalone`(自包含版)。
5. 版本号语义:新增功能升次版本号,修复升修订号。
---
## 七、关于体积
| 形态 | 精确大小 | 显示大小 | 依赖 |
| -------------- | --------------- | ------------------ | ----------------------- |
| 框架依赖单文件 | 286,387 字节 | 286 KB / 0.27 MiB| .NET 10 Desktop Runtime |
| 自包含单文件 | 69,821,117 字节 | 69.8 MB / 66.6 MiB | 无 |
体积构成与结论:
1. 精简版只打包自身程序集(约 0.3 MB),WPF 与运行时由系统共享。
2. 自包含版把 .NET 运行时、WPF 框架程序集和本地库一起塞进 exe,压缩后仍有 66.6 MiB,这是 WPF 应用的下限量级。
3. WPF 不支持 `PublishTrimmed`(IL 裁剪)与 NativeAOT,无法像控制台程序那样压到几 MB。
4. 曾尝试 `InvariantGlobalization` 去掉 ICU 数据,体积几乎没变(此前「省 3 MB」是 MB/MiB 单位误读),却导致 WPF 在中文输入法下崩溃,v1.1.1 已移除。结论:不要为了体积牺牲全球化支持。
5. 因此采用「双版本」策略:日常用精简版,给没有运行时的机器用自包含版。
---
## 八、注意事项
1. 精简版在未安装 .NET 10 Desktop Runtime 的机器上会弹出运行时下载提示,这是 apphost 的默认行为。
2. 自定义铃声与铃声库的解码依赖 Windows 自带解码器;flac/ogg 在部分精简系统上可能无声,但不会崩溃。
3. 铃声库只扫描所选文件夹的第一层,不递归子目录。
4. 响铃窗口只在主显示器全屏显示,多显示器场景下副屏不受影响。
5. 「跟随系统」主题只在启动时判断,运行中不监听系统主题变化。
6. 程序为单实例;重复启动会提示查看托盘,不会开第二个进程。
7. 响铃需要系统音量未静音;程序不修改系统音量。
8. 系统休眠/睡眠会暂停调度器计时,恢复后通过 `NextRing` 比对触发补提醒,最多补一次,不会连续轰炸。
9. 删除闹钟、导入覆盖等操作都会弹确认框;导入会覆盖当前全部闹钟。
10. 数据在 `%APPDATA%` 下,重装或换机前建议先「导出备份」。
11. 修改 `settings.json` 时请先退出程序,否则退出时可能被内存中的设置覆盖。
12. 首次启动自包含版会有短暂解压过程(单文件自解压),属正常现象。
---
## 九、版本历史
### v1.2.0(2026-11-03)铃声库
新增:
1. 全局铃声库文件夹设置,支持选择、打开、清空,显示曲目数。
2. 闹钟铃声新增「随机库」,每次响铃随机抽一首。
3. 随机不连播:排除上一首后再抽。
4. 库空或路径失效回退内置「晨光」。
5. 试听支持随机库;编辑面板实时显示库状态。
说明:随机库是全局设置,暂不支持每个闹钟独立文件夹;只扫描第一层目录。
### v1.1.1(2026-11-03)修复崩溃
修复:
1. 打开编辑面板、焦点进入时间输入框时报 `CultureNotFoundException`。
2. 根因:v1.1.0 开启 `InvariantGlobalization`,WPF 读取系统输入语言(中文 LCID 2052)时无法解析。
3. 处理:移除该开关,恢复完整全球化支持;体积无实质变化。
说明:这是一次典型的「优化引入回归」,也纠正了此前对体积收益的误判。
### v1.1.0(2026-11-03)试听与瘦身
新增:
1. 铃声试听按钮:循环播放、手动停止、12 秒自动结束。
2. 试听音量跟随滑块实时变化;切换铃声、关闭面板、响铃时自动停止。
优化:
1. 默认发布改为框架依赖单文件,从 69.8 MB 降到 286 KB。
2. 新增自包含单文件版本,供无运行时环境使用。
### v1.0.0(2026-11-03)首个版本
1. 闹钟增删改查与启停,按时间排序。
2. 重复规则:仅一次、每天、工作日、周末、自定义星期。
3. 全屏响铃,内置 3 种合成铃声,支持自定义音频文件。
4. 稍后提醒与防贪睡。
5. 音量调节、渐强音量。
6. 托盘常驻与托盘菜单。
7. 错过补提醒。
8. 倒计时与秒表(番茄钟预设、计次)。
9. 深色/浅色/跟随系统主题。
10. 开机自启。
11. JSON 导入导出、打开数据目录。
12. 全局快捷键、单实例保护。
13. 单文件自包含发布与自绘图标。
### 演进小结
| 版本 | 主题 | 关键风险 |
| ------ | ---------- | --------------------- |
| v1.0.0 | 从零到可用 | 调度边界、休眠恢复 |
| v1.1.0 | 体验与体积 | 单文件发布方式差异 |
| v1.1.1 | 稳定性修复 | 全球化开关与 WPF 冲突 |
| v1.2.0 | 铃声个性化 | 库路径失效、解码兼容|
---
## 十、后续可做
1. 节假日/调休日历,支持「法定工作日」重复规则。
2. 多显示器全屏响铃,覆盖所有屏幕。
3. 每个闹钟独立的铃声库文件夹。
4. 渐强时长可调(当前固定约 5 秒)。
5. 托盘菜单快速暂停单条闹钟。
6. 闹钟分组与搜索。
7. 响铃时系统音量联动(渐强到系统音量上限)。
## 下载地址
https://llii.lanzout.com/b00v0gc3cb
密码:8nbt 这玩意估计用的人真不多,比起手机,像我这种经常坐电脑前的人我都不想用win的提醒功能。。。 求一个求一个 分享链接 里面怎么是空的? 没有软件哦 链接是空的。。。 梦畅、心意闹钟还在用,体积小功能强,运行效率高资源占用低。 没有文件
啊?请问是出于什么原因要做一个win版的闹钟呢?真心求问。。 连接空的,忘记传了? 啥也没有
页:
[1]
2