Compare commits

..

942 Commits

Author SHA1 Message Date
CJK_mkp 045c29ca20 Merge pull request #236 from InkCanvasForClass/beta
ICC CE 1.7.12.0
2025-10-02 16:03:39 +08:00
CJKmkp 4ea6d19602 更新版本号 2025-10-02 15:58:33 +08:00
CJKmkp df00447c41 improve:启动动画 2025-10-02 15:36:52 +08:00
CJKmkp db5b1caea7 improve:启动动画 2025-10-02 15:35:53 +08:00
CJKmkp 8432954b8d add:issue #235 2025-10-02 15:30:51 +08:00
CJK_mkp 4a000e23e9 Update README.md 2025-10-02 15:09:27 +08:00
CJKmkp b42db51346 fix:忽略希沃白板五桌面批注窗口 2025-10-02 15:05:55 +08:00
CJKmkp 1ef968ea93 improve:悬浮窗拦截 2025-10-02 14:57:55 +08:00
CJKmkp 5b50537333 improve:开机动画 2025-10-02 14:53:57 +08:00
CJKmkp 8c624b48fb 删除无用信息 2025-10-02 14:08:22 +08:00
CJKmkp ad329fc2c8 improve:悬浮窗拦截 2025-10-02 11:50:00 +08:00
CJKmkp f045b8f659 fix:悬浮窗拦截 2025-10-02 11:45:55 +08:00
CJKmkp 00a9da45bb improve:启动动画 2025-10-02 02:59:49 +08:00
CJKmkp b7ecd12f8c improve:启动动画 2025-10-02 02:55:53 +08:00
CJKmkp a8a3164ee7 improve:启动动画 2025-10-02 02:44:45 +08:00
CJKmkp b1aec69e98 fix:issue #234 2025-10-02 02:32:29 +08:00
CJKmkp d713a8c5a4 优化注释 2025-10-02 02:30:24 +08:00
CJKmkp 3895faf941 fix:issue #133 2025-10-02 02:16:02 +08:00
CJKmkp bf336fdb10 add:issue #214 2025-10-02 02:11:54 +08:00
CJKmkp c96c26288c add:软件启动动画 2025-10-02 01:51:10 +08:00
CJKmkp 83558c089d add:软件启动动画 2025-10-02 00:17:11 +08:00
CJKmkp 26acb72e17 add:软件启动动画 2025-10-02 00:05:09 +08:00
CJKmkp 4724a432ab add:软件启动动画 2025-10-01 23:26:38 +08:00
CJKmkp 5b9c1627c0 add:软件启动动画 2025-10-01 22:38:40 +08:00
CJKmkp d06c2585cf add:软件启动动画 2025-10-01 22:24:49 +08:00
CJKmkp 3e96e51efd delete:office注册表修改 2025-10-01 22:06:23 +08:00
CJKmkp 9afa7191c4 fix:issue #232 2025-10-01 18:55:03 +08:00
CJKmkp dfddec5586 add:软件启动动画 2025-10-01 18:45:26 +08:00
CJKmkp 93022424b3 add:软件启动动画 2025-10-01 18:38:01 +08:00
CJKmkp aed77a187f add:软件启动动画 2025-10-01 18:17:39 +08:00
CJKmkp 583f47c98b 更新版本号 2025-10-01 15:20:14 +08:00
CJK_mkp ff528b3f9d Merge pull request #233 from InkCanvasForClass/beta
ICC CE 1.7.11.5
2025-10-01 15:17:17 +08:00
CJKmkp 6d98d96ccb fix:issue #217 2025-10-01 14:13:09 +08:00
CJKmkp 6f8e08c21a fix:issue #217 2025-10-01 13:03:11 +08:00
CJKmkp 3a7417f493 优化代码 2025-10-01 12:57:16 +08:00
CJKmkp 66164a0c33 improve:配置文件损坏自动恢复 2025-10-01 11:34:37 +08:00
CJKmkp 0d7a478e16 improve:配置文件损坏自动恢复 2025-10-01 11:29:59 +08:00
CJKmkp 9caef310df 优化代码 2025-10-01 10:04:40 +08:00
CJKmkp 688f742c16 add:老版UI切换 2025-10-01 09:52:15 +08:00
CJKmkp 38dd083cdc add:老版UI切换 2025-10-01 09:48:44 +08:00
CJKmkp 851bd1c3c6 improve:主题切换 2025-10-01 09:13:48 +08:00
CJKmkp c91b8a1a7a add:issue #224 2025-10-01 00:54:03 +08:00
CJKmkp 69c45764b2 Revert "add:issue #224"
This reverts commit 07a62d2f78.
2025-10-01 00:53:22 +08:00
CJKmkp 07a62d2f78 add:issue #224 2025-10-01 00:49:12 +08:00
CJKmkp 46b064b0a8 add:配置文件损坏自动恢复 2025-10-01 00:01:35 +08:00
CJKmkp 1d3b96bb65 更新Action 2025-09-30 23:45:40 +08:00
CJKmkp 916425b7f5 更新Action 2025-09-30 23:38:58 +08:00
CJKmkp 1c570ca242 fix:issue #210 2025-09-30 23:18:16 +08:00
CJKmkp ae41108971 优化代码 2025-09-30 22:56:32 +08:00
CJKmkp 395e7609a4 fix:issue #210 2025-09-30 22:55:06 +08:00
CJKmkp 185c9dc284 Reapply "fix:issue #201"
This reverts commit f40ef15a24.
2025-09-30 19:16:56 +08:00
CJKmkp a9b0ac0595 Revert "优化代码"
This reverts commit 92bb458345.
2025-09-30 19:15:03 +08:00
CJKmkp d9e3524211 fix:issue #201 2025-09-30 19:10:34 +08:00
CJKmkp f40ef15a24 Revert "fix:issue #201"
This reverts commit 9b5d157333.
2025-09-30 19:02:45 +08:00
CJKmkp 4d7544eefb deletefix:issue #210 2025-09-30 18:45:57 +08:00
CJKmkp 92bb458345 优化代码 2025-09-30 17:46:35 +08:00
CJKmkp 92e695ef7c fix:issue #213 2025-09-30 17:22:32 +08:00
CJKmkp 45ff3fbb9b fix:issue #213 2025-09-30 17:18:00 +08:00
CJKmkp ba252e92d3 fix:issue #229 2025-09-30 16:55:44 +08:00
CJK_mkp 4778f459e3 优化日志 2025-09-29 18:19:36 +08:00
CJK_mkp c997854ae0 优化日志 2025-09-29 18:14:39 +08:00
CJK_mkp 65b5322ad5 优化日志 2025-09-29 18:13:11 +08:00
CJK_mkp dd43bf0476 优化日志 2025-09-29 18:11:21 +08:00
CJKmkp 15c808eebd 更新版本号 2025-09-27 18:00:12 +08:00
CJKmkp 28748a99ca improve:手掌擦 2025-09-27 17:58:50 +08:00
CJKmkp fb37d3b9e6 improve:更新弹窗 2025-09-27 17:52:25 +08:00
CJKmkp e1f10e054c improve:issue #223 2025-09-27 17:09:06 +08:00
CJKmkp c670357c01 improve:橡皮擦 2025-09-27 17:01:33 +08:00
CJK_mkp 92dce9b36e Update MainWindow.xaml 2025-09-26 22:14:12 +08:00
PrefacedCorg aa2b62e8da 修复退出放映按钮字体显示不完全
把字体调小了()
2025-09-22 20:23:36 +08:00
CJKmkp a34a65f354 优化代码 2025-09-22 13:26:53 +08:00
CJKmkp eea5f8496c fix:高光显示 2025-09-22 13:11:22 +08:00
CJKmkp 091a256bcc Revert "Replace SymbolIcon with FontIcon throughout UI"
This reverts commit 37a69032f6.
2025-09-22 13:09:43 +08:00
CJKmkp 14c9ce3ce1 fix:issue #219 2025-09-22 12:32:53 +08:00
CJKmkp fd1e5e13fe fix:进入PPT自动收纳 2025-09-22 12:11:03 +08:00
CJKmkp 19685b8f95 fix:进入PPT自动收纳 2025-09-22 11:58:54 +08:00
CJKmkp a9da8dc10c fix:进入PPT自动收纳 2025-09-22 11:48:05 +08:00
CJKmkp fcfba7a978 fix:进入PPT自动收纳 2025-09-22 11:36:55 +08:00
PrefacedCorg 2c8c4351dd Update WenXiang.png 2025-09-25 10:26:38 +08:00
PrefacedCorg 79264b187d Remove unused exception variable in catch block
The exception variable 'ex' in the catch block was unused and has been removed for cleaner code.
2025-09-22 09:44:38 +08:00
PrefacedCorg 52eba9117b Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-22 09:34:45 +08:00
PrefacedCorg 37a69032f6 Replace SymbolIcon with FontIcon throughout UI
Updated all XAML and code-behind references from SymbolIcon/Symbol to FontIcon/Glyph for consistency and compatibility with the UI framework. This affects button icons, window controls, and shape drawing logic across multiple windows and components.
2025-09-22 09:34:39 +08:00
CJKmkp dd16b4f5a1 更新版本号 2025-09-21 08:28:32 +08:00
CJKmkp e9c20255a6 imporve:PPT墨迹保存 2025-09-21 08:26:55 +08:00
CJKmkp 630b4edf91 improve:PPT墨迹保存 2025-09-21 07:52:11 +08:00
CJKmkp 04ef638e17 fix:issue #190 2025-09-21 07:43:29 +08:00
CJKmkp 35bad240c2 更新版本号 2025-09-21 02:08:29 +08:00
CJKmkp 0cb4749cf3 add:主题切换 2025-09-21 02:05:49 +08:00
CJKmkp 7c8281eb00 add:主题切换 2025-09-21 01:35:13 +08:00
CJKmkp 1957288219 add:主题切换 2025-09-21 01:15:01 +08:00
CJKmkp c4d2b15c48 add:主题切换 2025-09-21 01:06:42 +08:00
CJKmkp beebfb0dae add:主题切换 2025-09-21 00:39:30 +08:00
CJKmkp d67172b795 优化代码 2025-09-21 00:28:30 +08:00
CJKmkp 2b012bc042 add:主题切换 2025-09-21 00:25:09 +08:00
CJKmkp 84da68f950 improve:历史版本回滚窗口 2025-09-20 22:27:26 +08:00
CJKmkp ad97fd13bf improve:更新弹窗 2025-09-20 22:21:05 +08:00
CJKmkp ebf6d0d5f7 improve:历史版本回滚窗口 2025-09-20 22:20:13 +08:00
CJKmkp 0f3b4b4384 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-20 22:02:43 +08:00
PrefacedCorg 226cf46d6b Merge pull request #212 from Hao3288/beta
readme文件中的部分url地址填写错误
2025-09-20 21:55:56 +08:00
CJKmkp 5689e33541 improve:更新弹窗 2025-09-20 21:54:02 +08:00
NoobHao 15e59e7117 Update README.md 2025-09-20 21:46:43 +08:00
NoobHao 6b538f6662 Update README.md 2025-09-20 21:45:38 +08:00
CJKmkp ad6808b696 improve:图片拖动 2025-09-20 21:33:21 +08:00
CJKmkp 8347b18efc 优化代码 2025-09-20 21:25:30 +08:00
CJKmkp f92b132f0a 优化代码 2025-09-20 19:49:16 +08:00
CJKmkp 79057d6757 fix:issue #160 2025-09-20 19:36:00 +08:00
CJKmkp a9b5ee8f62 fix:issue #205 2025-09-20 19:03:00 +08:00
CJKmkp 65da2c449e 更新版本号 2025-09-20 17:13:04 +08:00
CJKmkp 0ef8c12650 improve:issue #180 2025-09-20 17:06:11 +08:00
PrefacedCorg 1dfa48aecb Update MainWindow.xaml 2025-09-20 16:42:35 +08:00
PrefacedCorg b5d1713b43 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-20 16:36:02 +08:00
PrefacedCorg 102421997d add DeveloperAvatars 2025-09-20 16:34:55 +08:00
CJKmkp 43370bb8d1 fix:issue #202 2025-09-20 16:13:35 +08:00
CJKmkp 310f50fcde fix:issue #202 2025-09-20 16:10:52 +08:00
CJKmkp 9b5d157333 fix:issue #201 2025-09-20 15:36:45 +08:00
CJKmkp 53fbb7a0bd improve:更新弹窗 2025-09-20 15:36:24 +08:00
CJKmkp fe92117c4e improve:更新弹窗 2025-09-20 15:25:41 +08:00
CJKmkp 4a0d13457a improve:更新弹窗 2025-09-20 15:25:08 +08:00
CJKmkp 1ad6405003 improve:issue #197 2025-09-20 14:49:40 +08:00
CJKmkp 75e7e36011 improve:issue #133 2025-09-20 14:31:38 +08:00
CJKmkp 933c695b8c fix:issue #133 2025-09-20 14:02:29 +08:00
CJKmkp b34f7142f6 improve:墨迹平滑 2025-09-20 13:44:01 +08:00
CJKmkp 7392fa8165 fix:issue #204 2025-09-20 12:38:22 +08:00
CJKmkp 349d417869 fix:issue #205 2025-09-20 12:35:30 +08:00
CJKmkp b8e94cac9c fix:issue #210 2025-09-20 12:22:21 +08:00
CJKmkp cd90490b8d fix:issue #210 2025-09-20 12:15:21 +08:00
CJKmkp a9cc94ccb6 fix:issue #210 2025-09-20 12:03:30 +08:00
CJKmkp 17f137af09 fix:issue #210 2025-09-20 11:55:50 +08:00
CJKmkp ea7d0bbf71 fix:issue #206 2025-09-20 11:49:25 +08:00
CJKmkp 176f1cf405 fix:issue #208 2025-09-20 11:45:35 +08:00
CJKmkp 2ee93bbcc1 fix:issue #209 2025-09-20 11:42:33 +08:00
CJKmkp ba0629000e add:退出白板收纳 2025-09-20 11:22:09 +08:00
CJKmkp 313049f873 fix:issue #203 2025-09-20 11:08:52 +08:00
CJK_mkp d1a1b17d29 fix:白板参数 2025-09-18 18:07:45 +08:00
CJK_mkp eb91d2ce0a fix:白板参数 2025-09-18 18:06:53 +08:00
CJK_mkp 71c77da898 fix:issue #203 2025-09-18 17:58:51 +08:00
CJK_mkp 1b96c70386 fix:issue #160 2025-09-18 17:50:47 +08:00
CJK_mkp 703cecbd4f Merge pull request #196 from InkCanvasForClass/main
没事干合并一下commit
2025-09-13 23:15:56 +08:00
CJK_mkp e20bf41cc7 Merge pull request #195 from InkCanvasForClass/beta
ICC CE 1.7.11.0
2025-09-13 23:05:18 +08:00
CJKmkp 0f7b9524f9 fix:收纳模式下进入PPT自动进入批注异常 2025-09-13 22:53:31 +08:00
CJKmkp 53a9e901ec fix:退出PPT时错误的快捷键状态 2025-09-13 22:44:29 +08:00
CJKmkp 9a79fc71ed improve:PPT墨迹 2025-09-13 22:20:41 +08:00
CJKmkp e7f7a8038f 优化代码 2025-09-13 21:41:34 +08:00
CJKmkp 5361f8ae6f improve:墨迹延迟 2025-09-13 21:38:03 +08:00
CJKmkp ec3bcddc9d 更新版本号 2025-09-13 21:15:58 +08:00
CJKmkp 326a9f1d75 优化代码 2025-09-13 21:10:36 +08:00
CJKmkp 8c07e9b8a3 优化代码 2025-09-13 19:54:21 +08:00
CJKmkp 406d01febf 优化代码 2025-09-13 19:35:36 +08:00
CJKmkp 98663422b1 优化代码 2025-09-13 19:29:17 +08:00
CJKmkp 879dfcea28 add:issue #190 2025-09-13 19:10:40 +08:00
CJKmkp 40edb4c8de Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-13 18:53:49 +08:00
CJKmkp 07b6d142ad add:issue #190 2025-09-13 18:52:23 +08:00
2,2,3-三甲基戊烷 5716b3e3cf docs&fix: 移除ssh还存在于readme贡献者名单的bug 2025-09-13 18:45:59 +08:00
CJKmkp 1b242a07e1 delete:ssh 2025-09-13 18:29:13 +08:00
CJK_mkp 1516a73228 Merge pull request #192 from ShihaoShen2025/patch-1
删除all contributors src中有关hydro的信息
2025-09-13 18:22:46 +08:00
CJKmkp eef00eb28f add:issue #190 2025-09-13 18:20:56 +08:00
CJKmkp a5ac282ab6 add:issue #190 2025-09-13 18:13:31 +08:00
CJKmkp dbb88d4999 add:issue #190 2025-09-13 18:07:42 +08:00
电教沈同学 39addad3a1 Delete myself from ac-src
是时候给一切画上一个句号了。
再见,ICC-CE。
2025-09-13 17:58:06 +08:00
电教沈同学 87fd9a4470 Update .all-contributorsrc 2025-09-13 17:52:52 +08:00
电教沈同学 7a9156449f Update .all-contributorsrc 2025-09-13 17:50:36 +08:00
CJKmkp 6e2938e9c1 add:issue #190 2025-09-13 17:37:11 +08:00
CJKmkp 39e1498b26 add:issue #180 2025-09-13 16:36:41 +08:00
CJKmkp cc2dc9c1a7 add:issue #180 2025-09-13 16:28:31 +08:00
CJKmkp fa87198131 add:issue #180 2025-09-13 16:26:23 +08:00
CJKmkp 9b70b952f6 add:issue #180 2025-09-13 16:13:22 +08:00
CJKmkp b29fca1cdb add:issue #180 2025-09-13 16:09:51 +08:00
CJKmkp 501af800ce add:issue #180 2025-09-13 16:06:19 +08:00
CJKmkp 979be117c6 add:issue #180 2025-09-13 16:02:39 +08:00
CJKmkp 13594371bb add:issue #180 2025-09-13 15:34:50 +08:00
CJKmkp 9628d1b27f add:issue #181 2025-09-13 14:59:47 +08:00
CJKmkp fd0bd0b343 fix:托盘功能不可用 2025-09-13 14:33:49 +08:00
CJKmkp 9ea58bfdad 优化代码 2025-09-13 14:21:07 +08:00
CJKmkp c54d140107 improve:截图 2025-09-13 14:16:11 +08:00
CJKmkp 98d4a4213c improve:截图 2025-09-13 13:59:54 +08:00
CJKmkp a7d1de5ee3 improve:截图 2025-09-13 13:50:41 +08:00
CJKmkp fab9e4b265 improve:截图 2025-09-13 13:37:51 +08:00
CJKmkp d5fa46033e 优化日志 2025-09-13 13:03:04 +08:00
CJKmkp 32c179bbf9 improve:弹窗 2025-09-13 12:22:08 +08:00
CJKmkp 99f9886876 improve:直接调用外部点名 2025-09-13 12:08:45 +08:00
CJKmkp c1fcaff28a fix:issue #175 简易实现(后续会改) 2025-09-13 12:05:13 +08:00
CJKmkp 2da5e8d71b fix:动画导致的收纳问题 2025-09-13 11:56:26 +08:00
CJKmkp e80e64a287 fix:手势开关状态显示错误 2025-09-13 11:46:49 +08:00
CJKmkp 0344e51ef7 fix:issue #185 2025-09-13 11:38:46 +08:00
CJKmkp 9fd31b0584 improve:描述性文字 2025-09-13 11:32:08 +08:00
CJKmkp c6a48f79da fix:issue #184 2025-09-13 11:29:48 +08:00
CJKmkp 110d050cc6 fix:issue #188 2025-09-13 11:08:56 +08:00
CJKmkp 18188ef235 improve:弹窗 2025-09-13 11:04:04 +08:00
CJKmkp 3e1c397132 fix:issue #160 2025-09-13 10:58:43 +08:00
CJKmkp cda1f0b77d fix:无焦点功能状态丢失 2025-09-13 10:55:27 +08:00
CJKmkp afd49f154c improve:模式切换 issue #179 2025-09-13 10:51:08 +08:00
CJKmkp 505c620103 improve:PowerPoint联动增强 2025-09-13 10:48:33 +08:00
CJKmkp 5d9e340d6d improve:模式切换 issue #179 2025-09-13 10:46:02 +08:00
CJKmkp f705c4575c Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-13 10:43:50 +08:00
CJKmkp 1508bd806f 优化日志 2025-09-13 10:43:22 +08:00
CJK_mkp 1c542e0615 Update bug_report.yml 2025-09-12 15:59:11 +08:00
CJK_mkp ed5bcbde18 Update feature_request.yml 2025-09-12 15:58:36 +08:00
PrefacedCorg 084cbcd362 代码清理 2025-09-07 13:30:46 +08:00
CJKmkp ad8369cfe9 更新版本号 2025-09-07 13:25:20 +08:00
CJKmkp 7d36b3993e 优化代码 2025-09-07 09:41:42 +08:00
CJKmkp ead0854c8e improve:墨迹选择 2025-09-07 07:59:21 +08:00
CJKmkp 60b5655574 improve:墨迹选择 2025-09-07 07:53:05 +08:00
CJKmkp 9037630990 fix:issue #175 2025-09-07 01:50:44 +08:00
CJKmkp ba23fc9506 add:issue #171 2025-09-07 01:45:50 +08:00
CJKmkp 938ca7c0ea improve:墨迹选择 2025-09-07 01:22:46 +08:00
CJKmkp a034f7a9a0 improve:墨迹选择 2025-09-07 01:16:27 +08:00
PrefacedCorg d4c4fcfd74 Update PluginSettingsWindow.xaml 2025-09-07 01:02:34 +08:00
PrefacedCorg 5b457f2a8a 将插件管理器的页面改为无边框 2025-09-07 00:59:24 +08:00
CJKmkp adc22441fc fix:issue #173 2025-09-07 00:57:48 +08:00
CJKmkp 1ba59136c6 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-09-07 00:49:58 +08:00
CJKmkp 77702b2ac9 fix:issue #170 2025-09-07 00:49:10 +08:00
PrefacedCorg 0d6c814908 好像改错了() 2025-09-07 00:49:01 +08:00
PrefacedCorg 42ce58db60 贡献名单add PrefacedCorg(2) 2025-09-07 00:47:30 +08:00
PrefacedCorg 1ef56033fb 贡献名单add PrefacedCorg(1) 2025-09-07 00:31:22 +08:00
CJKmkp 8c1d3c0248 fix:issue #168 2025-09-07 00:20:48 +08:00
CJKmkp a725a12d25 fix:issue #169 2025-09-07 00:14:59 +08:00
CJKmkp f67db9beed fix:issue #178 #177 2025-09-07 00:11:22 +08:00
CJKmkp f22fd7b5d1 fix:issue #172 2025-09-07 00:08:11 +08:00
CJKmkp 060664260b fix:issue #172 2025-09-07 00:03:15 +08:00
CJKmkp 9da5ec7413 撤销操作 2025-09-06 23:58:00 +08:00
CJKmkp 076240f7cd 测试构建 2025-09-06 23:55:54 +08:00
CJKmkp d97a4ad243 fix:墨迹识别 2025-09-06 23:21:05 +08:00
CJKmkp 56209d8491 fix:issue #159 2025-09-06 22:22:41 +08:00
CJK_mkp 61fe7197f5 Merge pull request #166 from InkCanvasForClass/beta
ICC CE 1.7.10.0
2025-09-06 21:40:14 +08:00
CJKmkp 1881bfd69e 更新版本号 2025-09-06 21:35:07 +08:00
CJKmkp 4287b7def5 improve:用户分级 2025-09-06 21:33:06 +08:00
CJKmkp 27d683a7cc improve:PPT及自动更新 2025-09-06 21:26:46 +08:00
CJKmkp 38902c8f88 撤回操作 2025-09-06 20:59:45 +08:00
CJKmkp d8e8142ff4 发行说明测试 2025-09-06 20:57:24 +08:00
CJKmkp fdaf9cb3ef 发行说明测试 2025-09-06 20:37:05 +08:00
CJKmkp b2fe091c88 发行说明测试 2025-09-06 20:27:52 +08:00
CJKmkp 8548244cef 发行说明测试 2025-09-06 20:24:56 +08:00
CJKmkp 91a5881600 发行说明测试 2025-09-06 20:22:59 +08:00
CJKmkp 93fd043b14 发行说明测试 2025-09-06 20:21:24 +08:00
CJKmkp 47948ef530 更新版本号 2025-09-06 20:08:26 +08:00
CJKmkp 61fa618673 improve:用户分级 2025-09-06 20:02:50 +08:00
CJKmkp 545aecc6ae 更新版本号 2025-09-06 19:31:14 +08:00
CJKmkp ee41f53286 add:issue #156 2025-09-06 19:27:17 +08:00
CJKmkp cc8036f736 improve:无焦点 2025-09-06 18:12:45 +08:00
CJKmkp 67a982e6e4 improve:用户分级 2025-09-06 18:03:23 +08:00
CJKmkp b16000f8e5 improve:窗口置顶 2025-09-06 17:51:25 +08:00
CJKmkp a142ce0542 回滚操作 2025-09-06 17:41:34 +08:00
CJKmkp c87b8b65fc improve:高光显示 2025-09-06 17:12:25 +08:00
CJKmkp 7332df1d56 fix:issue #165 #133 及插件窗口问题 2025-09-06 15:50:16 +08:00
CJKmkp de90c17ab1 fix:issue #159 2025-09-06 15:36:40 +08:00
CJKmkp 3d54edf25b fix:issue #161 2025-09-06 15:28:14 +08:00
CJKmkp 111819dbf3 fix:issue #164 #155 2025-09-06 15:16:03 +08:00
CJKmkp 3665753ba2 优化日志 2025-09-06 15:14:53 +08:00
CJKmkp 75e38aa8f3 improve:issue #160 2025-09-06 15:09:34 +08:00
CJKmkp 29dc6938c3 improve:窗口置顶 2025-09-06 15:07:26 +08:00
CJKmkp 304933b02b improve:快捷键 2025-09-06 14:54:49 +08:00
CJKmkp 49f268bb62 improve:快捷键 2025-09-06 14:48:36 +08:00
CJKmkp d0793c546d improve:快捷键 2025-09-06 14:36:07 +08:00
CJKmkp 375aec6f6c improve:按钮显示 2025-09-06 14:24:18 +08:00
CJKmkp 12ec527dcd improve:浮动栏 2025-09-06 14:19:33 +08:00
CJKmkp 52d95173d7 improve:PPT模块及浮动栏 2025-09-06 14:18:09 +08:00
CJKmkp 67e3d51106 improve:窗口置顶 2025-09-06 13:58:49 +08:00
CJKmkp 9081aea926 improve:墨迹渐隐 2025-09-06 13:48:44 +08:00
CJKmkp 02c6caf465 fix:issue #153 2025-09-06 13:30:32 +08:00
CJKmkp 1a9ddf1969 improve:墨迹渐隐 2025-09-06 13:16:10 +08:00
CJKmkp 41bcae9d05 fix:issue #153 2025-09-06 12:38:57 +08:00
CJKmkp 28109a0c97 improve:PPT联动 2025-09-06 12:09:06 +08:00
CJKmkp d8825f0a73 fix:issue #154 2025-09-06 10:20:28 +08:00
CJKmkp 82c045a243 fix:issue #152 2025-09-06 10:17:12 +08:00
CJKmkp 4d11f69282 fix:issue #151 2025-09-06 10:11:19 +08:00
CJKmkp 664e4ea048 add:新设置 2025-08-31 17:11:04 +08:00
CJKmkp 6d21c5e24e add:新设置 2025-08-31 17:07:40 +08:00
CJKmkp ba21b6884d add:新设置 2025-08-31 16:25:52 +08:00
CJKmkp 60065aab3e add:新设置 2025-08-31 16:24:57 +08:00
CJKmkp 4d978936ac add:新设置 2025-08-31 16:17:21 +08:00
CJKmkp 4ea585633b add:新设置 2025-08-31 16:06:36 +08:00
CJKmkp dee0bd7f4d add:新设置 2025-08-31 15:58:58 +08:00
CJKmkp edb206ffa5 add:新设置 2025-08-31 15:35:28 +08:00
CJKmkp 21932056f3 improve:插件 2025-08-31 13:14:05 +08:00
CJK_mkp 0c3809b789 Merge pull request #147 from InkCanvasForClass/beta
ICC CE 1.7.9.1
2025-08-31 12:39:00 +08:00
CJKmkp d5ae596ad6 更新版本号 2025-08-31 12:37:49 +08:00
CJKmkp 42db7e60f2 improve:截图 2025-08-31 12:32:15 +08:00
CJKmkp 85827820a4 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-08-31 12:17:13 +08:00
CJKmkp fad2571edb fix:合并冲突 2025-08-31 12:16:29 +08:00
PrefacedCorg c53b6de68c Update ScreenshotSelectorWindow.xaml.cs 2025-08-31 12:14:46 +08:00
PrefacedCorg c86eb12168 Update YesOrNoNotificationWindow.xaml 2025-08-31 12:07:59 +08:00
CJKmkp fb31f8df11 优化代码 2025-08-31 12:05:26 +08:00
CJKmkp 147b4fc5ed improve:文件关联 2025-08-31 12:03:58 +08:00
CJKmkp cdcb2d2af0 add:文件关联 2025-08-31 11:49:00 +08:00
PrefacedCorg ff086e497c 代码清理 2025-08-31 11:43:52 +08:00
PrefacedCorg a2b711da05 改了个图标 2025-08-31 11:41:17 +08:00
CJKmkp 40ecfbefa3 improve:截图 2025-08-31 10:47:33 +08:00
CJK_mkp 2097a1250b Merge pull request #146 from InkCanvasForClass/beta
ICC CE 1.7.9.0
2025-08-31 10:24:44 +08:00
CJK_mkp 22025f9b00 Merge pull request #145 from InkCanvasForClass/beta
ICC CE 1.7.9.0
2025-08-31 10:22:57 +08:00
CJKmkp 80c1badba5 更新版本号 2025-08-31 10:08:49 +08:00
CJKmkp be308ba280 improve:截图 2025-08-31 10:06:11 +08:00
CJKmkp fa7f3d44e4 improve:截图及浮动栏 2025-08-31 09:59:49 +08:00
CJKmkp 9bb00489fe improve:截图及浮动栏及代码优化 2025-08-31 09:54:13 +08:00
CJKmkp 33948c604c improve:图片插入 2025-08-31 09:20:35 +08:00
CJKmkp b8fe5bbd66 improve:图片插入 2025-08-31 09:18:30 +08:00
CJKmkp 3fcc01c253 improve:图片插入 2025-08-31 09:15:53 +08:00
CJKmkp 658d48c17b improve:图片插入 2025-08-31 09:12:30 +08:00
CJKmkp 8d76c014c8 优化代码 2025-08-31 09:09:22 +08:00
CJKmkp 26cd125534 优化代码 2025-08-31 09:00:32 +08:00
CJKmkp 1bc23af61a 优化代码 2025-08-31 08:51:50 +08:00
CJKmkp a2aa6b48a8 improve:用户体验分级及图片插入 2025-08-31 08:04:46 +08:00
CJKmkp 5784c974f7 优化代码 2025-08-31 07:56:26 +08:00
CJKmkp 80503dc42e 优化代码 2025-08-31 07:54:43 +08:00
PrefacedCorg d76195f7ae fix:二级菜单下不去 2025-08-31 01:55:17 +08:00
PrefacedCorg 2fe482b802 让警告没那么多
应该不会出问题的吧
2025-08-31 01:47:00 +08:00
PrefacedCorg 16283f4643 添加空值检查 2025-08-31 01:00:59 +08:00
CJKmkp cd7a801400 还未完成的选择工具栏 2025-08-31 00:39:40 +08:00
CJKmkp f6d8558d07 improve:自动更新 2025-08-31 00:33:41 +08:00
CJKmkp de20b506f0 improve:用户体验分级 2025-08-31 00:25:22 +08:00
CJKmkp ea1d52292e improve:快捷键 2025-08-30 23:53:26 +08:00
CJKmkp 463e506ca3 improve:快捷键 2025-08-30 23:28:28 +08:00
CJKmkp 3bae64a2c7 improve:插入图片improve:插入图片 2025-08-30 23:19:53 +08:00
CJKmkp 5d13c8b543 improve:插入图片 2025-08-30 23:14:00 +08:00
CJKmkp c6c0789794 improve:自动更新 2025-08-30 23:10:02 +08:00
CJKmkp d7df39290f improve:插入图片及墨迹平滑 2025-08-30 22:59:12 +08:00
CJKmkp b64cefad46 improve:插入图片及墨迹平滑 2025-08-30 22:54:16 +08:00
CJKmkp 4690ab3c30 improve:插入图片 2025-08-30 22:14:39 +08:00
CJKmkp b61c7490b3 improve:截图 2025-08-30 21:23:36 +08:00
CJKmkp 9e511d29a6 delete:图片插入选中和移动相关 2025-08-30 21:18:34 +08:00
CJKmkp a9cdc36967 improve:长按翻页 2025-08-30 20:59:50 +08:00
CJKmkp 96c51cd7ff 优化代码 2025-08-30 19:40:14 +08:00
CJKmkp 636769c0ef fix:插入图片子面板折叠问题 2025-08-30 18:59:32 +08:00
CJKmkp 7beb2a3cc5 更新版本号 2025-08-30 18:49:31 +08:00
CJKmkp 52d318054c fix:部分情况高光错位 2025-08-30 18:48:46 +08:00
CJKmkp 5ee2ad6f3d improve:浮动栏动态调整 2025-08-30 18:36:20 +08:00
CJKmkp 097d414d0d fix:隐藏按钮导致的高光错位 2025-08-30 18:33:57 +08:00
CJK_mkp e0ce119374 Merge pull request #144 from InkCanvasForClass/beta
ICC CE 1.7.8.3
2025-08-30 18:24:09 +08:00
CJKmkp da9a5242cb 上传日志 2025-08-30 18:22:37 +08:00
CJKmkp 0211b38be9 更新版本号 2025-08-30 18:12:43 +08:00
CJKmkp 512e9b21cd improve:issue #143 2025-08-30 18:10:55 +08:00
CJKmkp 9181ad55ae fix:部分窗口无法点击 2025-08-30 16:25:10 +08:00
CJKmkp a1cb9e1b28 improve:自动更新 2025-08-30 16:10:20 +08:00
CJKmkp ea09a3e798 improve:自动更新 2025-08-30 15:49:37 +08:00
CJKmkp 21fa146f6f improve:自动更新 2025-08-30 15:28:51 +08:00
CJKmkp 1a3130041f improve:自动更新 2025-08-30 14:56:59 +08:00
CJKmkp 7095a5890c fix:issue #133 2025-08-30 14:53:50 +08:00
CJKmkp 4a86d1aa05 improve:自动更新 2025-08-30 14:11:39 +08:00
CJKmkp 19fe7223fb improve:快捷键 2025-08-30 11:34:29 +08:00
CJKmkp 8867fde3f2 fix:issue #141 2025-08-30 11:29:16 +08:00
CJKmkp 588d1822b1 fix:issue #141 2025-08-30 11:20:53 +08:00
CJK_mkp d2b3b38d9e fix:issue #141 2025-08-28 22:13:18 +08:00
CJK_mkp 206ae3d9ed fix:issue #141 2025-08-28 21:02:47 +08:00
CJK_mkp a67b7a2fd0 fix:issue #141 2025-08-28 20:13:43 +08:00
CJK_mkp f5a08b225c fix:issue #141 2025-08-28 18:35:17 +08:00
CJK_mkp c807f97c29 fix:issue #141 2025-08-28 18:32:47 +08:00
CJK_mkp 8382413137 fix:issue #141 2025-08-28 18:31:59 +08:00
CJK_mkp c6acafd3a6 fix:issue #141 2025-08-28 18:28:17 +08:00
CJK_mkp 9d43056361 fix:issue #141 2025-08-28 18:25:04 +08:00
CJK_mkp 52f8e24954 fix:issue #141 2025-08-28 18:24:12 +08:00
CJK_mkp dac05fec84 fix:issue #141 2025-08-28 18:20:44 +08:00
CJK_mkp cb4ed77572 fix:issue #141 2025-08-28 18:17:29 +08:00
CJK_mkp 3427cbdc2e fix:issue #141 2025-08-28 18:11:26 +08:00
CJK_mkp ec0fb0c3cf fix:issue #141 2025-08-28 18:10:52 +08:00
CJK_mkp 357983179c fix:issue #141 2025-08-28 18:07:39 +08:00
CJK_mkp 78b66c141e fix:issue #141 2025-08-28 18:05:20 +08:00
CJK_mkp 3ac88bb400 fix:issue #141 2025-08-28 18:02:44 +08:00
CJK_mkp 27493b857c 撤销更改 2025-08-28 17:41:29 +08:00
CJK_mkp e5a976abcf fix:issue #141 2025-08-28 17:37:08 +08:00
CJK_mkp 9e89bf5303 Merge pull request #142 from InkCanvasForClass/all-contributors/add-Jursin
docs: add Jursin as a contributor for design
2025-08-28 09:01:25 +08:00
allcontributors[bot] 54eb330711 docs: update .all-contributorsrc 2025-08-28 01:01:08 +00:00
allcontributors[bot] e9014c6f5d docs: update README.md 2025-08-28 01:01:07 +00:00
CJK_mkp 620bcf6fab fix:issue #140 2025-08-27 17:43:04 +08:00
CJK_mkp c03bbd9e13 fix:issue #140 2025-08-27 17:41:58 +08:00
CJK_mkp b428b4ec5b 回滚等待重构截图功能 2025-08-27 15:57:06 +08:00
CJK_mkp 876cc116ea fix:issue #140 2025-08-27 12:23:05 +08:00
CJK_mkp 0ba00c08ef fix:更新日志显示问题 2025-08-25 09:53:01 +08:00
CJK_mkp d41ecd9d55 fix:修正错误地址 2025-08-25 09:00:45 +08:00
CJK_mkp 35d351ce6b Merge pull request #138 from InkCanvasForClass/beta
ICC CE 1.7.8.0
2025-08-24 18:02:28 +08:00
CJKmkp 5d3af58361 fix:浮动栏动画异常 2025-08-24 18:01:04 +08:00
CJKmkp 8554b92f42 improve:外部点名 2025-08-24 17:26:26 +08:00
CJKmkp 76363b4263 更新版本号 2025-08-24 16:29:51 +08:00
CJKmkp b4250b9161 fix:开关状态显示错误 2025-08-24 16:24:29 +08:00
CJKmkp 441f40886f fix:issue #133 2025-08-24 16:09:14 +08:00
CJKmkp e8e8ad5d63 更新版本号 2025-08-24 12:13:55 +08:00
CJKmkp 454078ec82 add:更多插件支持 2025-08-24 12:02:29 +08:00
CJK_mkp 63f29c2686 Merge pull request #137 from InkCanvasForClass/beta
ICC CE 1.7.7.7
2025-08-24 11:58:06 +08:00
CJKmkp 280445f613 fix:浮动栏动画异常 2025-08-24 11:47:39 +08:00
CJKmkp d7f6433b53 更新版本号 2025-08-24 11:09:41 +08:00
CJKmkp 22da4cc408 fix:无焦点无法翻页 2025-08-24 11:08:13 +08:00
CJKmkp 4e185ef584 improve:长按翻页 2025-08-24 10:39:24 +08:00
CJKmkp fd9b4b4ba6 improve:墨迹渐隐开关 2025-08-24 10:17:21 +08:00
CJKmkp 2f79bbcb0f fix:错误的唤起URL 2025-08-24 09:46:52 +08:00
CJKmkp 2c70d243df improve:墨迹渐隐开关 2025-08-24 09:33:27 +08:00
CJKmkp 7710b77255 improve:快捷键和墨迹渐隐 2025-08-24 09:17:58 +08:00
CJKmkp d1eed23399 improve:快捷键 2025-08-24 09:09:48 +08:00
CJKmkp ff9ce4df44 imrpove:快捷键 2025-08-24 08:45:53 +08:00
CJKmkp b7c52842f2 improve:快捷键 2025-08-24 02:30:38 +08:00
CJKmkp 365459f649 improve:快捷键 2025-08-24 02:27:57 +08:00
CJKmkp e6354f724f 优化日志 2025-08-24 02:03:34 +08:00
CJKmkp 14eedca939 fix:时间戳问题 2025-08-24 01:46:48 +08:00
CJKmkp 83529cfe09 add:issue #135 #136 2025-08-24 00:05:26 +08:00
CJKmkp bd4e1c1810 更新版本号 2025-08-23 23:32:44 +08:00
CJKmkp 5665fcc823 add:issue #131 2025-08-23 23:13:39 +08:00
CJKmkp 710a9014dd improve:issue #112 2025-08-23 21:39:00 +08:00
CJKmkp 108c6b2b17 improve:使用数据保存 2025-08-23 20:24:48 +08:00
CJKmkp 70735943c3 add:长按翻页 2025-08-23 19:43:09 +08:00
CJKmkp d01a24f879 add:底部翻页控件预览 2025-08-23 19:32:13 +08:00
CJKmkp ec2d5043ff add:底部PPT翻页按钮调节 2025-08-23 19:27:30 +08:00
CJKmkp 15082c2c52 fix:墨迹出现在不对应的PPT文档上 2025-08-23 19:16:19 +08:00
CJKmkp 44278d68b4 fix:翻页控件不合理的显示时机 2025-08-23 19:10:53 +08:00
CJKmkp 40eeb9db66 fix:退出放映模式后浮动栏异常问题 2025-08-23 19:04:46 +08:00
CJKmkp a5eb1dfca7 fix:开启部分功能后手势面板显示异常 2025-08-23 18:58:57 +08:00
CJKmkp 8719677f11 fix:开启部分功能后手势面板显示异常 2025-08-23 18:55:36 +08:00
CJKmkp 8f01b6c5fe fix:切换时荧光笔状态异常 2025-08-23 18:51:16 +08:00
CJKmkp 9e63a3f49b fix:快捷调色板不支持荧光笔 2025-08-23 18:43:47 +08:00
CJKmkp 84edb7bbe6 fix:快捷调色板不支持荧光笔 2025-08-23 18:39:12 +08:00
CJKmkp c86ce00a17 fix:快捷调色板不支持荧光笔 2025-08-23 18:29:24 +08:00
CJKmkp aba6c18a25 fix:issue #133 2025-08-23 18:24:24 +08:00
2,2,3-三甲基戊烷 62c81e6d44 Merge pull request #134 from InkCanvasForClass/all-contributors/add-PrefacedCorg 2025-08-23 10:44:32 +08:00
allcontributors[bot] 68ea323855 docs: update .all-contributorsrc 2025-08-23 02:44:15 +00:00
allcontributors[bot] f94d81ad20 docs: update README.md 2025-08-23 02:44:14 +00:00
CJK_mkp 063f8b1751 优化日志 2025-08-19 18:04:45 +08:00
CJK_mkp 35cfd26ece fix:退出不完全时更新 2025-08-19 17:52:02 +08:00
CJK_mkp f331cb1b4d fix:issue #110 2025-08-19 17:41:42 +08:00
CJK_mkp 502e205071 fix:关机时不保存使用数据 2025-08-18 18:01:23 +08:00
CJK_mkp 975b563b8d fix:关机时不保存使用数据 2025-08-18 17:57:56 +08:00
CJK_mkp cc88630859 fix:关机时不保存使用数据 2025-08-18 17:54:41 +08:00
CJK_mkp cce0b930ec fix:关机时不保存使用数据 2025-08-18 17:49:33 +08:00
CJK_mkp 723c825df2 fix:关机时不保存使用数据 2025-08-18 17:42:36 +08:00
CJK_mkp 5b4c966354 优化日志 2025-08-13 22:03:18 +08:00
CJK_mkp 69023f98d9 优化日志 2025-08-13 22:00:53 +08:00
CJK_mkp dce5722e96 优化日志 2025-08-13 21:59:35 +08:00
CJK_mkp cbdbc93274 Merge pull request #127 from InkCanvasForClass/beta
ICC CE 1.7.7.5
2025-08-13 14:29:53 +08:00
CJKmkp 042b153684 improve:窗口置顶 2025-08-13 12:52:56 +08:00
CJKmkp 4054423721 更新版本号 2025-08-13 12:37:27 +08:00
CJKmkp 2e63a6eaca improve:面积擦子面板显示位置 2025-08-13 12:31:58 +08:00
CJKmkp 9eca7eb2ee fix:插入图片面板点击空白不折叠 2025-08-13 12:16:55 +08:00
CJKmkp 1489fb645e add:橡皮子面板中的清空按钮,更符合操作逻辑 2025-08-13 12:11:44 +08:00
CJKmkp 5c0ca841d7 fix:调色盘导致的按钮高光显示错位 2025-08-13 11:54:36 +08:00
CJKmkp a4d3d3ff9c 删除无用文件 2025-08-13 10:28:54 +08:00
CJKmkp c3b67f4a4b 更新版本号 2025-08-12 15:51:26 +08:00
CJKmkp cde5daf19a add:issue #126 2025-08-12 15:45:33 +08:00
CJKmkp 904b2c0988 add:issue #124 2025-08-12 15:33:19 +08:00
CJKmkp f9907e2ec6 improve:按钮显示控制 2025-08-12 12:50:29 +08:00
CJKmkp 7329c0097c improve:快捷调色盘 2025-08-12 12:30:48 +08:00
CJKmkp 0478949305 improve:快捷调色盘 2025-08-12 12:19:55 +08:00
CJKmkp 34172a54fe 更新版本号 2025-08-12 11:14:24 +08:00
CJKmkp 6dd629eda5 improve:快捷调色盘 2025-08-12 11:13:35 +08:00
CJKmkp 636dd2b8d5 add:快捷调色盘 2025-08-12 11:08:24 +08:00
CJKmkp b20dbc5202 更新版本号 2025-08-11 22:48:25 +08:00
CJKmkp ee45104eb9 improve:快捷调色盘 2025-08-11 22:47:43 +08:00
CJKmkp 152be89860 add:按钮显示控制 2025-08-11 22:42:36 +08:00
CJKmkp 6b5a375542 更新版本号 2025-08-11 21:49:29 +08:00
CJKmkp 03d049846d 更新版本号 2025-08-11 20:32:12 +08:00
CJKmkp 6ed084bb94 add:快捷调色盘 2025-08-11 20:28:33 +08:00
CJKmkp f5332b63a9 add:快捷调色盘 2025-08-11 20:23:14 +08:00
CJKmkp 87356215c3 add:快捷调色盘 2025-08-11 20:19:01 +08:00
CJKmkp 07c7acc37a add:按钮显示控制 2025-08-11 19:18:21 +08:00
CJKmkp 4a6d9dee67 add:按钮显示控制 2025-08-11 19:08:05 +08:00
CJKmkp 52eb93e59c 更新版本号 2025-08-11 11:38:35 +08:00
CJKmkp 2245a018e6 fix:触摸线擦 2025-08-11 09:13:12 +08:00
CJKmkp 8b327fd715 fix:几何触摸绘制 2025-08-10 14:08:07 +08:00
CJKmkp 7a7289a4c8 更新版本号 2025-08-10 12:21:24 +08:00
CJKmkp ceb259819f fix:几何触摸绘制 2025-08-10 12:20:51 +08:00
CJKmkp fdfbaedbd7 fix:几何触摸绘制 2025-08-10 11:58:58 +08:00
PrefacedCorg 9591fbf146 我也不知道我改了啥 2025-08-09 13:16:22 +08:00
CJKmkp b2a09dbf6d fix:几何墨迹问题 2025-08-04 20:25:42 +08:00
PrefacedCorg 11a5a7fdbe 代码清理 2025-08-03 16:46:33 +08:00
PrefacedCorg 745b798d89 Update MainWindow.xaml 2025-08-03 15:23:46 +08:00
PrefacedCorg 7bac32e3c4 Update MainWindow.xaml 2025-08-01 02:56:53 +08:00
PrefacedCorg 880ca08571 fix time 2025-08-01 02:56:24 +08:00
PrefacedCorg 85d4d8a71e 修复二级菜单移位
修复二级菜单移位(和优化江陵写的屎山)
2025-07-31 20:38:30 +08:00
CJKmkp abb8ed0bcc fix:插入图片 2025-07-31 16:49:53 +08:00
CJKmkp bea0d10a6c Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-07-31 16:36:42 +08:00
CJK_mkp 80d943af23 Merge pull request #123 from InkCanvasForClass/beta-PrefacedCorg
合并分支
2025-07-31 15:22:18 +08:00
PrefacedCorg 90b85e469d Update MainWindow.xaml 2025-07-31 15:07:39 +08:00
PrefacedCorg 0d419c1323 fix 二级菜单移位 2025-07-31 14:52:44 +08:00
PrefacedCorg f7a2ecc2e0 给二级菜单加了个x :( 2025-07-31 14:12:49 +08:00
PrefacedCorg 5fdbf83f32 新增图片选择选项 2025-07-31 13:23:33 +08:00
CJKmkp c513ad9291 improve:插入图片 2025-07-31 10:55:01 +08:00
CJKmkp a2dfa55dbd improve:插入图片 2025-07-31 10:27:19 +08:00
CJKmkp 78f8d9a271 fix:退出确认按钮 2025-07-31 10:03:29 +08:00
CJK_mkp b25a5aac8c Merge pull request #122 from MKStoler1024/beta
fix: gitignore
2025-07-31 09:46:24 +08:00
MKStoler1024 25cc70035e fix: gitignore 2025-07-31 09:39:46 +08:00
MKStoler1024 e5d70d5a0e del: unneeded files 2025-07-31 09:38:07 +08:00
MKStoler1024 066b0d1f8a fix: gitignore 2025-07-31 09:35:00 +08:00
CJKmkp 71b2e56187 improve:截图功能 2025-07-30 20:06:43 +08:00
CJKmkp 457832fbbe improve:截图功能 2025-07-30 20:06:29 +08:00
CJKmkp 00554e066b add:截图功能 2025-07-30 19:56:22 +08:00
CJKmkp 9f9775e585 fix:图片插入 2025-07-30 14:18:45 +08:00
CJKmkp 9cf70ae74e fix:图片插入 2025-07-30 14:12:10 +08:00
CJKmkp 4f046987c6 fix:线擦切换至批注的面板弹出及高光显示问题 2025-07-30 13:24:52 +08:00
CJKmkp 699666c23b fix:issue #120 2025-07-29 23:14:20 +08:00
CJKmkp 6a8cdd0155 fix:issue #118 2025-07-29 19:07:59 +08:00
CJKmkp ce61f0e2b7 improve:IACore 2025-07-29 19:00:45 +08:00
CJKmkp b3cb0bf93f improve:IACore 2025-07-29 19:00:32 +08:00
CJKmkp 07328eea2d Revert "delete:IACore释放"
This reverts commit bfb6346812.
2025-07-29 18:37:00 +08:00
CJK_mkp 5f7a6f2e07 Merge pull request #119 from InkCanvasForClass/beta
ICC CE 1.7.6.0
2025-07-29 18:19:26 +08:00
CJKmkp 39d54cc493 更新版本号 2025-07-29 18:06:59 +08:00
CJKmkp d31f40408b fix:图片墨迹保存问题 2025-07-29 17:59:41 +08:00
CJKmkp 7f88d9ae27 fix:图片墨迹保存问题 2025-07-29 17:44:15 +08:00
CJKmkp 1c1dd81474 fix:图片墨迹保存问题 2025-07-29 17:38:58 +08:00
CJKmkp 53a498c581 fix:IACore 2025-07-29 16:28:22 +08:00
CJKmkp bfb6346812 delete:IACore释放 2025-07-29 16:08:24 +08:00
CJKmkp bd2fa1e427 improve:PPT模块 2025-07-29 09:43:18 +08:00
CJKmkp 6c4bfeff29 improve:PPT模块 2025-07-29 09:35:47 +08:00
CJKmkp 299a77eea8 improve:PPT模块 2025-07-29 09:19:27 +08:00
CJKmkp 351a00fb1e 更新版本号 2025-07-29 09:08:39 +08:00
CJKmkp 2140e1ebe1 improve:墨迹平滑 2025-07-29 09:02:03 +08:00
CJKmkp 497a820ba2 improve:PPT模块 2025-07-29 08:44:17 +08:00
CJKmkp 7182f3554a Revert "fix:issue #110"
This reverts commit f8e4732dcd.
2025-07-29 02:33:19 +08:00
CJKmkp 506ba52502 improve:直线拉直 2025-07-29 01:40:35 +08:00
CJKmkp 90c1630af4 improve:PPT模块 2025-07-29 01:34:51 +08:00
CJKmkp 5934abd448 fix:进退白板墨迹消失 2025-07-29 01:31:21 +08:00
CJKmkp 86f432ef01 improve:PPT模块 2025-07-29 01:24:42 +08:00
CJKmkp 4913019c5c 优化PPT模块 2025-07-29 01:15:32 +08:00
CJKmkp a6316797e6 更新软件信息 2025-07-29 00:01:47 +08:00
CJKmkp 00d7549bde 更新互斥锁 2025-07-28 23:57:50 +08:00
CJKmkp 8fc33f5649 更新软件名称 2025-07-28 23:51:14 +08:00
CJKmkp 729b544675 improve:PPT模块 2025-07-28 22:36:02 +08:00
CJK_mkp 865415a6c0 Merge pull request #113 from InkCanvasForClass/beta
ICC CE 1.7.5.0
2025-07-28 19:16:24 +08:00
CJKmkp 32e8324275 更新日志 2025-07-28 19:12:12 +08:00
CJKmkp 842f6dd726 更新版本号 2025-07-28 19:10:51 +08:00
CJKmkp 59f7d11df3 improve:单文件 2025-07-28 19:08:06 +08:00
CJKmkp dcd2f52c59 improve:插入图片 2025-07-28 19:02:45 +08:00
CJKmkp b45413c232 fix:墨迹纠正失效 2025-07-28 18:29:22 +08:00
CJKmkp b4481ff680 fix:issue #111 2025-07-28 18:23:07 +08:00
CJKmkp d7d7a3919f improve:日志输出 2025-07-28 18:11:20 +08:00
CJKmkp f8e4732dcd fix:issue #110 2025-07-28 17:44:15 +08:00
CJKmkp 1b92ed66b7 更新README 2025-07-28 16:19:19 +08:00
CJKmkp 9ba74b9504 更新版本号 2025-07-28 16:12:40 +08:00
CJKmkp 8cd49f12d1 更新README 2025-07-28 16:10:40 +08:00
CJKmkp c48ca9ee89 fix:issue #93 2025-07-28 16:04:36 +08:00
CJKmkp 43bcf71bf5 fix:issue #93 2025-07-28 15:47:18 +08:00
CJKmkp ee48813df1 fix:issue #93 2025-07-28 15:18:33 +08:00
CJKmkp f4a67e2822 fix:issue #93 2025-07-28 14:45:37 +08:00
CJKmkp f03733da04 优化代码 2025-07-28 14:40:44 +08:00
CJK_mkp 207560bcc7 Merge pull request #109 from InkCanvasForClass/beta
ICC CE 1.7.4.1
2025-07-28 11:46:23 +08:00
CJKmkp f38313ff2c 更新版本号 2025-07-28 11:37:58 +08:00
CJKmkp b5d9e21f37 improve:用户体验分级 2025-07-28 11:35:47 +08:00
CJKmkp 5d42a8957e fix:issue #93 2025-07-28 11:15:35 +08:00
CJK_mkp b276c60909 Merge pull request #108 from InkCanvasForClass/all-contributors/add-PrefacedCorg
docs: add PrefacedCorg as a contributor for code
2025-07-28 02:05:44 +08:00
allcontributors[bot] d03564bce9 docs: update .all-contributorsrc 2025-07-27 18:05:04 +00:00
allcontributors[bot] 41409c39d5 docs: update README.md 2025-07-27 18:05:03 +00:00
CJK_mkp aa9c5107d0 Merge pull request #107 from PrefacedCorg/beta
fix:issue #93
2025-07-28 02:02:57 +08:00
PrefacedCorg 7a141822e7 fix:issue #93 2025-07-28 01:49:54 +08:00
CJKmkp a4fd301d5a fix:issue #93 2025-07-28 00:48:50 +08:00
CJKmkp b2ef8b96ef fix:issue #93 2025-07-27 22:52:04 +08:00
CJKmkp baa9e1003e fix:issue #93 2025-07-27 22:00:37 +08:00
CJK_mkp 5d17a586d5 Merge pull request #106 from InkCanvasForClass/beta
ICC CE 1.7.4.0
2025-07-27 16:20:53 +08:00
CJKmkp 36b97b2adc 更新版本号 2025-07-27 16:15:36 +08:00
CJKmkp f13bffa834 add:优化至单文件版本 2025-07-27 16:05:38 +08:00
CJKmkp 4394566ed3 fix:issue #105 2025-07-27 00:13:41 +08:00
2,2,3-三甲基戊烷 de95c24f66 fix: Fix the problems of the bandage of STCN 2025-07-26 19:42:27 +08:00
CJK_mkp 6058cb9cff Merge pull request #104 from InkCanvasForClass/beta
ICC CE 1.7.3.0
2025-07-26 19:38:22 +08:00
CJKmkp 6b20d3e268 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-07-26 19:37:12 +08:00
CJKmkp ce037a437a 更新版本号 2025-07-26 19:36:39 +08:00
2,2,3-三甲基戊烷 1349dab6d4 fix: Update README.md 2025-07-26 19:35:16 +08:00
CJKmkp d3d31925ee Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-07-26 19:34:22 +08:00
CJKmkp d9fa77c86b 更新版本号 2025-07-26 19:34:06 +08:00
CJKmkp dad01235b0 fix:侧边栏中的退出放映按钮退出不完全的问题 2025-07-26 19:30:56 +08:00
2,2,3-三甲基戊烷 52d9c26076 Merge pull request #103 from InkCanvasForClass/all-contributors/add-awesome-iwb
docs: add awesome-iwb as a contributor for doc
2025-07-26 19:26:01 +08:00
allcontributors[bot] 1a0236237d docs: update .all-contributorsrc 2025-07-26 11:25:43 +00:00
allcontributors[bot] 58bb7a5ebc docs: update README.md 2025-07-26 11:25:42 +00:00
CJK_mkp efbab58bca Merge pull request #102 from InkCanvasForClass/all-contributors/add-Alan-CRL
docs: add Alan-CRL as a contributor for financial
2025-07-26 19:20:37 +08:00
2,2,3-三甲基戊烷 eedbc7a863 Merge branch 'beta' into all-contributors/add-Alan-CRL 2025-07-26 19:20:26 +08:00
allcontributors[bot] 626cda63ff docs: update .all-contributorsrc 2025-07-26 11:17:27 +00:00
allcontributors[bot] 7b7a9d93aa docs: update README.md 2025-07-26 11:17:26 +00:00
2,2,3-三甲基戊烷 f5c68dac61 Merge pull request #101 from InkCanvasForClass/all-contributors/add-MKStoler1024
docs: add MKStoler1024 as a contributor for doc, code, and design
2025-07-26 19:16:22 +08:00
allcontributors[bot] 2b6b106771 docs: update .all-contributorsrc 2025-07-26 11:15:47 +00:00
allcontributors[bot] 047586883e docs: update README.md 2025-07-26 11:15:46 +00:00
2,2,3-三甲基戊烷 0c1a25dd6b feat: Merge pull request #100 from InkCanvasForClass/all-contributors/add-Alan-CRL
docs: add Alan-CRL as a contributor for code, infra, and doc
2025-07-26 19:11:45 +08:00
allcontributors[bot] 7840a9a713 docs: update .all-contributorsrc 2025-07-26 11:11:01 +00:00
allcontributors[bot] 28f96ffcd3 docs: update README.md 2025-07-26 11:11:00 +00:00
CJKmkp 04b2663183 improve:墨迹平滑 2025-07-26 19:03:07 +08:00
2,2,3-三甲基戊烷 1a11027871 feat: Merge pull request #99 from InkCanvasForClass/all-contributors/add-2-2-3-trimethylpentane
docs: add 2-2-3-trimethylpentane as a contributor for blog, doc, and design
2025-07-26 19:00:48 +08:00
allcontributors[bot] 854a00803e docs: update .all-contributorsrc 2025-07-26 11:00:10 +00:00
allcontributors[bot] 11ae5f157f docs: update README.md 2025-07-26 11:00:09 +00:00
CJKmkp ecfe05139e improve:插件功能 2025-07-26 18:37:08 +08:00
CJKmkp 4a392e03a7 更新版本号 2025-07-26 16:24:30 +08:00
CJKmkp a66037f886 improve:用户体验分级 2025-07-26 16:22:55 +08:00
CJKmkp 58c399dcbe improve:用户体验分级 2025-07-26 16:08:22 +08:00
CJKmkp f33e617f44 improve:用户体验分级 2025-07-26 15:57:28 +08:00
CJKmkp 3e976c1026 improve:用户体验分级 2025-07-26 15:01:00 +08:00
CJKmkp c15c75075c improve:用户体验分级 2025-07-26 15:00:31 +08:00
CJKmkp bf8d988c75 improve:用户体验分级 2025-07-26 14:58:10 +08:00
CJKmkp 6fb7af3d46 add:用户体验分级 2025-07-26 14:29:24 +08:00
CJKmkp 1c2860c180 更新版本号 2025-07-26 12:41:44 +08:00
CJKmkp fc41f10c37 improve:自动更新 2025-07-26 12:37:39 +08:00
CJKmkp dedf366866 improve:自动更新 2025-07-26 12:33:08 +08:00
CJKmkp edb10096d6 improve:自动更新 2025-07-26 12:20:23 +08:00
CJKmkp ba42a1e6c9 improve:自动更新 2025-07-26 12:02:58 +08:00
CJK_mkp f5f989d140 Merge pull request #98 from InkCanvasForClass/beta
ICC CE 1.7.2.0
2025-07-25 18:45:27 +08:00
CJKmkp a0058c104d 更新日志 2025-07-25 18:36:23 +08:00
CJKmkp 7f1f322d04 improve:白板时间显示 2025-07-25 18:32:03 +08:00
CJKmkp 57ac8d8771 更新版本号 2025-07-25 18:28:38 +08:00
CJKmkp bcd0509eff improve:窗口无焦点 2025-07-25 18:21:16 +08:00
CJKmkp 624af87795 fix:侧边栏显示及浮动栏高度计算 2025-07-25 18:12:46 +08:00
CJKmkp 616df56657 improve:任务栏高度计算 2025-07-25 18:02:46 +08:00
CJKmkp 4efd6abb56 improve:任务栏高度计算 2025-07-25 17:57:04 +08:00
CJKmkp 8c657a4ccf improve:PPT模块 2025-07-25 17:50:07 +08:00
CJKmkp db582f6c88 更新版本号 2025-07-25 11:07:12 +08:00
CJKmkp a7b861f83c improve:PPT模块 2025-07-25 10:21:55 +08:00
CJKmkp 19b1c7ae8b improve:PPT模块 2025-07-25 09:58:53 +08:00
CJKmkp 192cec68c7 improve:自动更新 2025-07-24 23:18:44 +08:00
CJK_mkp 3541522fc6 Merge pull request #97 from InkCanvasForClass/beta
ICC CE 1.7.1.14
2025-07-24 22:27:06 +08:00
CJKmkp 4afa66f3f3 更新版本号 2025-07-24 22:18:31 +08:00
CJKmkp 7fde157184 improve:自动更新 2025-07-24 22:16:38 +08:00
CJKmkp a1935e8299 improve:直线拉直 2025-07-24 21:02:00 +08:00
CJKmkp 50e993fd89 improve:直线拉直 2025-07-24 20:59:21 +08:00
CJKmkp a25ec6b0af fix:白板使用擦除后出现的线条异常BUG 2025-07-24 02:02:34 +08:00
CJKmkp efeb99aaac fix:触摸时长方体绘制多余直线 2025-07-24 00:58:03 +08:00
CJKmkp f19118432d improve:自动保存 2025-07-24 00:20:00 +08:00
CJKmkp b69eac2886 improve:默认设置 2025-07-23 23:16:49 +08:00
CJKmkp 4efc4e7f34 improve:默认配置文件 2025-07-23 23:14:29 +08:00
CJKmkp 4755eb06e2 improve:手掌擦 2025-07-23 23:12:37 +08:00
CJKmkp e4dc1c0b4e improve:手掌擦 2025-07-23 23:10:10 +08:00
CJKmkp 89f54c2b4a 更新版本号 2025-07-23 23:06:39 +08:00
CJKmkp abf52f0d49 add:新版手掌擦 2025-07-23 23:05:28 +08:00
CJKmkp 044df3f09c delete:手掌擦 2025-07-23 22:57:16 +08:00
CJKmkp 271829f9c1 Revert "improve:手掌擦"
This reverts commit eb0cf27218.
2025-07-23 22:16:43 +08:00
CJKmkp 13625b37a8 improve:自动更新 2025-07-23 21:45:29 +08:00
CJK_mkp cceadd2a3d Merge pull request #96 from InkCanvasForClass/beta
ICC CE 1.7.1.12
2025-07-23 19:52:01 +08:00
CJKmkp 781191196f 更新版本号 2025-07-23 19:44:06 +08:00
CJKmkp eb0cf27218 improve:手掌擦 2025-07-23 19:42:41 +08:00
CJKmkp 1706341283 improve:自动更新 2025-07-23 19:29:44 +08:00
CJKmkp 71f46b3bff improve:自动更新 2025-07-22 22:39:02 +08:00
CJKmkp 4c39798682 improve:设置界面 2025-07-22 22:02:21 +08:00
CJKmkp b861aa385d improve:设置界面 2025-07-22 21:39:22 +08:00
CJKmkp 156e8a2686 improve:自动更新 2025-07-22 21:01:25 +08:00
CJKmkp f88acf1375 improve:设置页面 2025-07-22 19:06:35 +08:00
CJKmkp be770d4607 improve:自动更新 2025-07-22 18:45:43 +08:00
CJKmkp 7565f624c9 improve:自动更新 2025-07-22 18:36:37 +08:00
CJKmkp 65d56297fd improve:自动更新 2025-07-22 18:25:04 +08:00
CJKmkp 86caac4a1d improve:自动更新 2025-07-22 18:08:22 +08:00
CJKmkp d382ac4fa2 improve:自动更新 2025-07-22 18:02:29 +08:00
CJKmkp f9ceeaad44 improve:自动更新 2025-07-22 17:36:02 +08:00
CJKmkp 0691293973 improve:自动更新 2025-07-22 17:07:27 +08:00
CJKmkp 9491b48eb6 improve:窗口无焦点 2025-07-22 16:20:37 +08:00
CJKmkp 6c7f63270f improve:白板时间显示 2025-07-22 16:12:42 +08:00
CJKmkp a62f793288 improve:设置 2025-07-21 22:45:55 +08:00
CJK_mkp 5fc715b7d0 Merge pull request #95 from InkCanvasForClass/beta
ICC CE 1.7.10
2025-07-21 22:33:53 +08:00
CJKmkp 901b54b829 更新版本号 2025-07-21 21:39:08 +08:00
CJKmkp 0efa1127a3 fix:issue #94 2025-07-21 21:02:23 +08:00
CJKmkp 28fc53799a fix:issue #92 #94 2025-07-21 20:30:07 +08:00
CJKmkp bdc4af7cd4 improve:任务栏高度计算 2025-07-21 18:53:47 +08:00
CJKmkp c68996ff20 improve:手掌擦 2025-07-21 18:39:42 +08:00
CJKmkp f517a63cda improve:手掌擦 2025-07-21 18:37:25 +08:00
CJKmkp fefb9b490e 更新版本号 2025-07-21 18:13:27 +08:00
CJKmkp 383e1d5368 improve:鸿合屏幕书写查杀后自动进入批注 #38 2025-07-21 17:57:08 +08:00
CJKmkp 4e4ce36e76 add:鸿合屏幕书写查杀后自动进入批注 #38 2025-07-21 17:28:52 +08:00
CJKmkp 19983a113e add:进入PPT放映自动回到首页 #38 2025-07-21 17:19:27 +08:00
CJKmkp 8eaac465ff improve:退出PPT放映自动恢复收纳模式 #38 2025-07-21 17:08:17 +08:00
CJKmkp 17b2d744ba add:退出PPT放映自动恢复收纳模式 #38 2025-07-21 16:53:11 +08:00
CJKmkp 166e0d400a add:侧边栏退出放映按钮 #38 2025-07-21 16:43:29 +08:00
CJKmkp 5cf409ce0b improve:PPT模块 2025-07-21 16:15:42 +08:00
CJKmkp e37e847a8b 删除无用using 2025-07-21 16:00:31 +08:00
CJKmkp 32c77d3743 improve:插入图片 2025-07-21 15:20:05 +08:00
CJKmkp 45e368d9e7 fix:issue #91 2025-07-21 14:35:30 +08:00
CJKmkp 97496302fb improve:插入照片 2025-07-21 14:19:55 +08:00
CJKmkp 675959e615 improve:插入图片 2025-07-21 12:44:05 +08:00
CJKmkp f641b282b6 improve:插入图片 2025-07-21 12:15:56 +08:00
CJKmkp e92a05683c add:插入图片 2025-07-21 11:37:20 +08:00
CJKmkp 93bef2e144 fix:白板页面预览无法使用触摸 2025-07-21 10:14:21 +08:00
CJKmkp 44e331ae96 fix:issue #91 2025-07-21 09:56:51 +08:00
CJKmkp f295c85668 fix:issue #90 2025-07-21 09:54:58 +08:00
CJKmkp 6f843bface improve:PPT模块 2025-07-21 08:43:16 +08:00
CJKmkp 2dea6076f0 improve:PPT模块 2025-07-21 08:37:37 +08:00
CJKmkp 78c6c7b571 improve:手掌擦 2025-07-20 22:54:49 +08:00
CJKmkp a50bec9326 improve:插件图标 2025-07-20 22:40:55 +08:00
CJKmkp 7d193d7de6 fix:错误的侧边栏按钮 2025-07-20 21:49:47 +08:00
CJKmkp 5bbb3e6a6c fix:错误的侧边栏按钮 2025-07-20 21:43:03 +08:00
CJK_mkp 32c1ddab46 Merge pull request #88 from InkCanvasForClass/beta
ICC CE 1.7.1.6
2025-07-20 21:22:04 +08:00
CJKmkp 15198c32ea improve:PPT模块 2025-07-20 21:14:59 +08:00
CJKmkp 476503338f improve:窗口无焦点 2025-07-20 21:03:42 +08:00
CJKmkp ba6303dca0 improve:窗口无焦点 2025-07-20 21:01:15 +08:00
CJKmkp 23432465ac improve:PPT模块 2025-07-20 19:52:59 +08:00
CJKmkp 1f0b5cebeb improve:PPT模块 2025-07-20 19:40:10 +08:00
CJKmkp 1f83c84a7e improve:PPT模块 2025-07-20 19:36:58 +08:00
CJKmkp e209af9c57 improve:PPT模块 2025-07-20 19:31:01 +08:00
CJKmkp a714d312a8 improve:PPT日志输出 2025-07-20 19:23:43 +08:00
CJKmkp 4a776c1fe8 improve:墨迹平滑方案 2025-07-20 19:17:32 +08:00
CJKmkp da86f07cbe fix:PPT墨迹对应问题 2025-07-20 18:27:08 +08:00
CJKmkp 48e0ca887d improve:PPT联动模块 2025-07-20 17:20:33 +08:00
CJKmkp 0f3b6c4cec improve:墨迹平滑方案 2025-07-20 16:48:16 +08:00
CJKmkp 9ce9631135 更新版本号 2025-07-20 16:16:17 +08:00
CJKmkp c73a5c3a7e fix:翻页控件崩溃 2025-07-20 16:14:26 +08:00
CJKmkp 62d35127b1 improve:墨迹平滑方案 2025-07-20 15:57:51 +08:00
CJKmkp 09f17caabe fix:白板颜色无法保存的问题 2025-07-20 15:42:11 +08:00
CJKmkp c5355d7497 improve:墨迹平滑方案 2025-07-20 15:27:02 +08:00
CJKmkp d5142ad82c improve:墨迹平滑方案 2025-07-20 15:21:59 +08:00
CJKmkp 428b278c78 更新版本号 2025-07-20 15:02:03 +08:00
CJKmkp 33c1e04934 improve:issue #5 2025-07-20 15:00:11 +08:00
CJKmkp 6c075d80ba improve:issue #5 2025-07-20 12:36:21 +08:00
CJKmkp 38713108e0 improve:issue #5 2025-07-20 12:19:32 +08:00
CJKmkp 6b75fea813 improve:issue #5 2025-07-20 12:01:30 +08:00
CJKmkp de6fc84fec Revert "improve:联动模块"
This reverts commit ecd276a3a0.
2025-07-20 09:09:39 +08:00
CJKmkp ecd276a3a0 improve:联动模块 2025-07-20 00:37:13 +08:00
CJKmkp 86fbd0cebc 撤回模块改进 2025-07-20 00:25:33 +08:00
CJKmkp 6a97919f7a Revert "improve:联动模块"
This reverts commit f2e7e17bd1.
2025-07-20 00:21:16 +08:00
CJKmkp f2e7e17bd1 improve:联动模块 2025-07-20 00:16:23 +08:00
CJKmkp eedd6cee1d improve:联动模块 2025-07-20 00:13:21 +08:00
CJKmkp 25e11fa9de improve:联动模块 2025-07-20 00:09:48 +08:00
CJKmkp 4742600b86 improve:联动模块 2025-07-19 23:42:43 +08:00
CJKmkp b3e4850413 improve:插件图标 2025-07-19 22:01:02 +08:00
CJK_mkp 1085f6c57a Merge pull request #87 from InkCanvasForClass/beta
ICC CE 1.7.1.3
2025-07-19 17:41:15 +08:00
CJKmkp fd8d13447c 更新版本号 2025-07-19 17:31:08 +08:00
CJKmkp 758a3d3f99 improve:issue #79 2025-07-19 17:27:27 +08:00
CJKmkp fd8b4d94d6 improve:issue #79 2025-07-19 17:21:59 +08:00
CJKmkp fa7dae8177 fix:win7无法自动更新 2025-07-19 16:51:03 +08:00
CJKmkp 21638218c6 improve:启动台插件 2025-07-19 16:37:44 +08:00
CJKmkp a29a414e8a improve:issue #79 2025-07-19 16:21:03 +08:00
CJKmkp 251c7f399e improve:自动更新 2025-07-19 16:03:45 +08:00
CJKmkp 1da55f2011 improve:自动更新 2025-07-19 15:36:05 +08:00
CJKmkp 856125edc2 更新版本号 2025-07-19 14:35:33 +08:00
CJKmkp 32ef30ebd8 improve:橡皮图标 2025-07-19 14:34:06 +08:00
CJKmkp 8972e42fee Revert "improve:橡皮光标"
This reverts commit 91f206aad0.
2025-07-19 14:10:29 +08:00
CJKmkp 91f206aad0 improve:橡皮光标 2025-07-19 14:04:35 +08:00
CJKmkp 5626babcdf improve:橡皮光标 2025-07-19 13:36:42 +08:00
CJKmkp 98175152db improve:光标显示 2025-07-19 13:35:28 +08:00
CJKmkp 817ade3e34 improve:光标显示 2025-07-19 10:56:30 +08:00
CJKmkp ab5493f8c4 improve:光标显示 2025-07-19 10:18:16 +08:00
CJKmkp 796bd99377 improve:插件功能 2025-07-18 21:51:32 +08:00
CJKmkp a0dc60a403 improve:联动模块 2025-07-18 21:29:55 +08:00
CJKmkp a92e58abf1 improve:白板画布 2025-07-18 19:20:06 +08:00
CJKmkp e8f0793feb 更新版本号 2025-07-18 18:52:01 +08:00
CJKmkp 2d7eff8205 fix:触摸问题 2025-07-18 17:59:17 +08:00
CJKmkp 6412892985 fix:触摸问题 2025-07-18 17:02:17 +08:00
CJKmkp 69ae0ffc71 fix:触摸问题 2025-07-18 17:01:18 +08:00
CJKmkp 854be23cfb fix:触摸问题 2025-07-18 16:28:50 +08:00
CJKmkp 02e143217e fix:触摸问题 2025-07-18 16:21:39 +08:00
CJKmkp 4feec82b03 fix:触摸问题 2025-07-18 16:12:04 +08:00
CJKmkp 938ca648f1 撤销操作 2025-07-18 11:53:55 +08:00
CJKmkp ee018ea287 撤销 Commit ab88c34 2025-07-18 11:50:44 +08:00
CJKmkp 8ab60ad000 撤销 Commit ab88c34 2025-07-18 11:49:00 +08:00
CJKmkp 17eaf34500 撤销 Commit b46cbcc 2025-07-18 11:47:41 +08:00
CJKmkp 2485958f6e 撤销Commit 3645906 2025-07-18 11:38:32 +08:00
CJKmkp 7ac3a22fa6 improve:插件功能 2025-07-17 22:30:12 +08:00
CJKmkp 285f211f50 add:备份功能 2025-07-16 15:28:36 +08:00
CJK_mkp e9ec424625 Merge pull request #86 from InkCanvasForClass/beta
ICC CE 1.7.1.0
2025-07-16 14:09:49 +08:00
CJKmkp 1e96477127 更新版本号 2025-07-16 14:04:40 +08:00
CJKmkp 87ffa48265 improve:插件功能 2025-07-16 14:02:54 +08:00
CJKmkp 8b64df435c improve:插件功能 2025-07-16 13:50:32 +08:00
CJKmkp dcf88ee510 improve:插件功能 2025-07-16 13:39:24 +08:00
CJKmkp b21a15376d add:插件功能 2025-07-16 13:35:17 +08:00
CJKmkp 3e87ed4f9b add:墨迹全屏保存 #79 2025-07-16 09:49:41 +08:00
CJKmkp a6cd9c955b 更新版本号 2025-07-16 09:17:46 +08:00
CJKmkp 86b52b76ed add:自定义白板背景色 #39 2025-07-16 09:16:36 +08:00
CJKmkp 853f380e5d improve:手掌擦机制 2025-07-16 08:03:08 +08:00
CJKmkp 027686a3b5 更新版本号 2025-07-15 21:43:44 +08:00
CJKmkp 79b87e59be improve:设置侧边栏 2025-07-15 21:10:49 +08:00
CJKmkp 3a37e55162 add:退出收纳模式自动进入批注选项 2025-07-15 21:00:00 +08:00
CJKmkp 1ff40c0016 add:自定义点名背景 2025-07-15 20:50:12 +08:00
CJKmkp 4f7c1021c8 improve:自定义图标保存了位置 2025-07-15 20:33:47 +08:00
CJKmkp e687c78ba8 add:自定义浮动栏图标 2025-07-15 20:30:10 +08:00
CJKmkp 2c2f46a0d8 improve:端点吸附 2025-07-15 18:30:25 +08:00
CJKmkp 29fa565258 fix:issue #75 2025-07-15 18:09:38 +08:00
CJKmkp 51f3d410c9 fix:issue #47 2025-07-15 17:55:22 +08:00
CJKmkp a0d159da9d improve:进程检测 2025-07-15 16:06:29 +08:00
CJKmkp 9edb58ee27 improve:自动更新 2025-07-15 14:36:54 +08:00
CJK_mkp a8de65ab0e Merge pull request #85 from InkCanvasForClass/beta
合并分支
2025-07-15 14:11:29 +08:00
CJK_mkp ef8a894489 Merge pull request #84 from InkCanvasForClass/all-contributors/add-CreeperAWA
All contributors/add creeper awa
2025-07-15 14:09:46 +08:00
allcontributors[bot] 992f388a56 docs: update .all-contributorsrc 2025-07-14 08:23:15 +00:00
allcontributors[bot] a54e7206a0 docs: update README.md 2025-07-14 08:23:14 +00:00
Hydrogen c4e74b21fc Merge pull request #82 from InkCanvasForClass/all-contributors/add-Hydro11451
docs: add Hydro11451 as a contributor for code
2025-07-14 16:22:51 +08:00
allcontributors[bot] 7b9e07bdda docs: update .all-contributorsrc 2025-07-14 08:22:19 +00:00
allcontributors[bot] 19f5204253 docs: update README.md 2025-07-14 08:22:18 +00:00
Hydrogen c4ad5c5f81 Merge pull request #81 from InkCanvasForClass/all-contributors/add-CJKmkp
docs: add CJKmkp as a contributor for code
2025-07-14 16:21:27 +08:00
allcontributors[bot] e888118a20 docs: update .all-contributorsrc 2025-07-14 08:21:08 +00:00
allcontributors[bot] 7afce136f6 docs: update README.md 2025-07-14 08:21:07 +00:00
Hydrogen 71c4dadeee Delete myself from All Contributors
我已经退出ICC-CE管理组。——Hydrogen
2025-07-14 16:19:40 +08:00
CJK_mkp c6a95c99ef Merge pull request #80 from InkCanvasForClass/beta
合并分支
2025-07-14 08:58:57 +08:00
Hydrogen a6d44685b3 Update README.md 2025-07-14 08:42:19 +08:00
CJK_mkp a8ce61dad9 Update Settings.cs 2025-07-12 17:33:13 +08:00
CJK_mkp 0f47d1473d Update Settings.cs 2025-07-12 17:32:05 +08:00
CJK_mkp 2134ee516a Update Settings.cs 2025-07-12 15:59:09 +08:00
CJK_mkp 6c60306bee Update MW_Settings.cs 2025-07-12 12:16:41 +08:00
CJK_mkp 816748833c Update MainWindow.xaml 2025-07-12 12:14:43 +08:00
CJK_mkp cac0fca3bb Update MW_Settings.cs 2025-07-12 10:49:24 +08:00
CJK_mkp 5ed28b121e Update MW_PPT.cs 2025-07-12 09:09:20 +08:00
CJK_mkp c4180eba6f Update MW_Save&OpenStrokes.cs 2025-07-12 09:01:49 +08:00
CJK_mkp 0065a1f81f Update MW_Screenshot.cs 2025-07-12 09:00:51 +08:00
CJK_mkp e1f3a6ada4 Merge pull request #78 from InkCanvasForClass/beta
合并分支
2025-07-10 21:04:50 +08:00
CJK_mkp ed7ffbcb13 Merge pull request #77 from 2-2-3-trimethylpentane/beta
fix: correct the URL in the poster
2025-07-10 21:03:56 +08:00
2,2,3-三甲基戊烷 6a8d9db407 Rename ICC-CE宣传图.png to icc ce.png 2025-07-10 11:41:46 +08:00
2,2,3-三甲基戊烷 81140837f1 fix: Delete Images/icc ce.png 2025-07-10 11:41:20 +08:00
2,2,3-三甲基戊烷 70232645a8 fix: correct the URL in the picture 2025-07-10 11:38:51 +08:00
CJK_mkp 4d3b3ef3df Update MW_TouchEvents.cs 2025-07-06 22:07:05 +08:00
CJK_mkp d203314424 Update MW_FloatingBarIcons.cs 2025-07-06 21:09:01 +08:00
CJK_mkp b95da2d8d5 Merge pull request #76 from InkCanvasForClass/beta
ICC CE Beta 1.7.0.4
2025-07-06 16:24:32 +08:00
CJK_mkp a8c5ccda17 更新版本号 2025-07-06 16:23:33 +08:00
CJK_mkp 86b996637c fix:崩溃后重启选项无法修改,部分触摸问题 improve::自动更新 2025-07-06 15:39:37 +08:00
DotteringDoge471 1480d4a14e Update README.md 2025-07-05 23:13:16 +08:00
Hydrogen 8586735ca8 Merge pull request #74 from InkCanvasForClass/beta
Beta
2025-07-05 22:25:30 +08:00
Hydrogen b8013afd64 Merge pull request #73 from InkCanvasForClass/all-contributors/add-CJKmkp
docs: add CJKmkp as a contributor for doc
2025-07-05 22:25:04 +08:00
allcontributors[bot] 812bc83939 docs: update .all-contributorsrc 2025-07-05 14:24:19 +00:00
allcontributors[bot] d6829744bb docs: update README.md 2025-07-05 14:24:18 +00:00
CJK_mkp a7a03544b6 Merge pull request #72 from InkCanvasForClass/main
合并分支
2025-07-03 22:12:55 +08:00
DotteringDoge471 ffa8729d10 Merge pull request #71 from CreeperAWA/issue_template 2025-07-03 04:24:02 +08:00
CreeperAWA ce291d3a77 improve:删除旧的 Bug 报告和功能请求模板,添加新的 .yml 格式模板以方便用户填写 2025-06-30 19:02:32 +08:00
CJK_mkp 297dbad60c Merge pull request #67 from InkCanvasForClass/beta
ICC CE Beta 1.7.0.3 更新合并
2025-06-29 16:42:40 +08:00
CJK_mkp 54982218f5 更新版本号 2025-06-29 16:25:32 +08:00
CJK_mkp c14f4df494 Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-06-29 16:00:42 +08:00
CJK_mkp f53f23aa4b improve:更新日志格式 2025-06-29 16:00:37 +08:00
CJK_mkp 10c59fb4b4 Update UpdateLog.md 2025-06-29 15:59:31 +08:00
CJK_mkp a5cffc5ea4 Rename UpdateLog.txt to UpdateLog.md 2025-06-29 15:58:21 +08:00
CJK_mkp 200c299ce7 fix:数位笔相关问题 2025-06-29 15:45:18 +08:00
CJK_mkp 8547276549 fix:手掌擦面积问题 2025-06-29 15:35:28 +08:00
CJK_mkp b09afcf725 fix:修复板擦面积问题 2025-06-29 15:29:25 +08:00
CJK_mkp a2860be7a3 fix:issue #40 2025-06-29 15:15:51 +08:00
CJK_mkp de9d026e3a Merge branch 'beta' of https://github.com/InkCanvasForClass/community into beta 2025-06-29 15:07:17 +08:00
CJK_mkp 27a1baae7b fix:修复了自动收纳的相关问题 2025-06-29 15:07:13 +08:00
Hydrogen f2584309d1 Merge pull request #66 from InkCanvasForClass/beta
Beta
2025-06-29 15:04:10 +08:00
Hydrogen 831fd09615 Update gesture-enabled icon
Replaces the existing gesture-enabled.png icon with a new version in the Resources/new-icons directory.
2025-06-29 15:01:42 +08:00
Hydrogen e0e22a09c0 Update gesture icon image
Replaces the existing gesture.png icon in Resources/new-icons with a new version.
2025-06-29 14:52:19 +08:00
CJK_mkp 60c6e0632d add:高精度直线拉直 2025-06-29 14:15:20 +08:00
CJK_mkp 6da13c4fc0 add:直接调Ci点名 2025-06-29 13:01:33 +08:00
CJK_mkp ec330aea69 improve:改进日志功能 2025-06-29 12:40:15 +08:00
CJK_mkp 318682b63a fix:版本修复按钮 2025-06-29 12:20:45 +08:00
CJK_mkp dd53d7ff0a Merge pull request #62 from InkCanvasForClass/beta
Update UpdateLog.txt
2025-06-29 12:09:00 +08:00
CJK_mkp b03207d287 Update UpdateLog.txt 2025-06-29 12:06:46 +08:00
CJK_mkp 7db87b7c36 Merge pull request #61 from InkCanvasForClass/beta
ICC CE 1.7.0.0 (ICC CE Beta1.7.0.0)
2025-06-29 12:01:50 +08:00
CJK_mkp 54d0aaca04 improve:改进自动更新 2025-06-29 11:56:38 +08:00
CJK_mkp 352aa886c8 Merge pull request #60 from InkCanvasForClass/main
合并分支
2025-06-29 10:18:20 +08:00
Hydrogen 8fada629f0 Update README.md 2025-06-29 09:21:08 +08:00
Hydrogen 34bb3cd0bd Merge pull request #59 from InkCanvasForClass/beta
Beta
2025-06-29 09:12:42 +08:00
Hydrogen 5555a67422 Merge pull request #58 from InkCanvasForClass/all-contributors/add-Hydro11451
docs: add Hydro11451 as a contributor for doc
2025-06-29 09:11:46 +08:00
allcontributors[bot] 3631d35946 docs: update .all-contributorsrc 2025-06-29 01:04:17 +00:00
allcontributors[bot] 460d4a5ac1 docs: update README.md 2025-06-29 01:04:16 +00:00
Hydrogen b7b5db18fd Update .all-contributorsrc 2025-06-29 09:03:45 +08:00
Hydrogen 58d877af6b Update README.md 2025-06-29 09:02:19 +08:00
Hydrogen ab20e0d8f2 Update .all-contributorsrc 2025-06-29 09:02:00 +08:00
Hydrogen 42e55c51b0 Update .all-contributorsrc 2025-06-29 08:57:00 +08:00
Hydrogen ca82c24c76 Merge pull request #57 from InkCanvasForClass/revert-56-all-contributors/add-Hydro11451
Revert "docs: add Hydro11451 as a contributor for doc"
2025-06-29 08:56:25 +08:00
Hydrogen 66874e7a85 Revert "docs: add Hydro11451 as a contributor for doc" 2025-06-29 08:55:59 +08:00
Hydrogen e365a94f71 Update README.md 2025-06-29 08:52:42 +08:00
Hydrogen 81298e5980 Merge pull request #55 from InkCanvasForClass/beta
Beta
2025-06-29 08:51:59 +08:00
Hydrogen 4eb920553b Merge pull request #56 from InkCanvasForClass/all-contributors/add-Hydro11451
docs: add Hydro11451 as a contributor for doc
2025-06-29 08:51:44 +08:00
Hydrogen 1be5408302 Update .all-contributorsrc 2025-06-29 08:51:04 +08:00
allcontributors[bot] 1e9a7b037a docs: update .all-contributorsrc 2025-06-29 00:49:32 +00:00
allcontributors[bot] e79ed438ef docs: update README.md 2025-06-29 00:49:31 +00:00
Hydrogen ff658409be Update README.md 2025-06-29 08:43:52 +08:00
dubi906w 9c26353fed fix: gitignore and purge. 2025-06-29 01:55:52 +08:00
CJK_mkp 2a3ce9549a Create UpdateLog.txt 2025-06-28 22:09:24 +08:00
CJK_mkp 8093f55b4f Merge pull request #54 from InkCanvasForClass/main
合并分支
2025-06-28 22:03:16 +08:00
Hydrogen 4a46892486 修改ac badge样式 2025-06-28 21:57:41 +08:00
DotteringDoge471 35fafc39a8 Merge pull request #52 from InkCanvasForClass/all-contributors/add-Hydro11451
docs: add Hydro11451 as a contributor for maintenance
2025-06-28 21:11:36 +08:00
allcontributors[bot] 3976970bb5 docs: update .all-contributorsrc 2025-06-28 13:09:17 +00:00
allcontributors[bot] 1a3ab49849 docs: update README.md 2025-06-28 13:09:15 +00:00
CJK_mkp 32d75ae23d Merge pull request #51 from InkCanvasForClass/all-contributors/add-CJKmkp
docs: add CJKmkp as a contributor for maintenance
2025-06-28 21:08:17 +08:00
CJK_mkp 29c6844390 Merge pull request #50 from InkCanvasForClass/beta
Beta
2025-06-28 21:07:20 +08:00
allcontributors[bot] 9c6eee59a8 docs: update .all-contributorsrc 2025-06-28 13:06:42 +00:00
allcontributors[bot] 4ff2be67d3 docs: update README.md 2025-06-28 13:06:41 +00:00
CJK_mkp 47d3eb13ce Update AssemblyInfo.cs 2025-06-28 21:06:26 +08:00
CJK_mkp 5de3043544 Update AssemblyInfo.cs 2025-06-28 21:05:02 +08:00
CJK_mkp 4b1d544c6b Update AutomaticUpdateVersionControl.txt 2025-06-28 21:04:09 +08:00
Hydrogen 6cb8fe3a6e Update README.md 2025-06-28 21:02:13 +08:00
CJK_mkp 1acf2e044e Merge pull request #49 from InkCanvasForClass/beta
合并分支
2025-06-28 21:01:43 +08:00
Hydrogen 9e9e960fa3 修修补补x4
啊啊啊啊啊啊啊
2025-06-28 20:29:08 +08:00
Hydrogen e767873ff1 Create .all-contributorsrc 2025-06-28 20:28:01 +08:00
Hydrogen b57762afed Update README.md
shields.io需要亿点点尝逝
2025-06-28 20:24:06 +08:00
Hydrogen 24526c5a48 Update README.md 2025-06-28 20:23:07 +08:00
Hydrogen ed1b62ec50 Update README.md 2025-06-28 20:22:49 +08:00
Hydrogen 98e727cf55 修修补补x3
《梅开三度》
2025-06-28 20:20:21 +08:00
Hydrogen 6c4ed850b0 修修补补x2
《梅开二度》(这个词是这么用的吧)
2025-06-28 20:17:56 +08:00
CJK_mkp db6b9da945 Merge pull request #48 from InkCanvasForClass/beta
合并分支
2025-06-28 20:17:38 +08:00
Hydrogen 52c930624a 修修补补 2025-06-28 20:16:32 +08:00
Hydrogen b7ddcb5419 增加极为先进的allcontributors 2025-06-28 20:15:36 +08:00
CJK_mkp 34f27c8e8d Update bug_report.md 2025-06-28 20:14:13 +08:00
CJK_mkp 3f7055327b Update MainWindow.xaml 2025-06-28 20:13:20 +08:00
CJK_mkp 51fb13b448 Merge pull request #46 from InkCanvasForClass/beta
合并分支
2025-06-28 09:01:21 +08:00
CJK_mkp 5273990305 Update README.md 2025-06-28 08:59:52 +08:00
CJK_mkp a44badddaa Update README.md 2025-06-28 08:56:02 +08:00
CJK_mkp 3e8d186dc8 Update README.md 2025-06-28 08:53:20 +08:00
CJK_mkp 51f8a0541d Add files via upload 2025-06-28 08:52:34 +08:00
CJK_mkp 808da0a3a7 Merge pull request #45 from InkCanvasForClass/beta
Update README.md
2025-06-27 16:50:50 +08:00
CJK_mkp 1c522840cd Update README.md 2025-06-27 16:50:22 +08:00
CJK_mkp 6fb8506551 Merge pull request #44 from InkCanvasForClass/beta
合并分支
2025-06-27 16:48:57 +08:00
CJK_mkp 7bf0438960 Update MainWindow.xaml 2025-06-27 16:47:13 +08:00
CJK_mkp fe02ec1852 Update HasNewUpdateWindow.xaml 2025-06-27 16:46:05 +08:00
CJK_mkp 4020925af1 Merge pull request #43 from InkCanvasForClass/beta
Update README.md
2025-06-24 17:25:22 +08:00
CJK_mkp 863b42f516 Update README.md 2025-06-24 17:22:23 +08:00
CJK_mkp 7f6b03be27 Merge pull request #42 from InkCanvasForClass/beta
合并分支,修改部分内容
2025-06-24 17:18:07 +08:00
CJK_mkp 880770b718 Merge branch 'main' into beta 2025-06-24 17:17:55 +08:00
CJK_mkp ed74f98919 Update README.md 2025-06-24 17:08:46 +08:00
CJK_mkp 4a1e42d5ee Update AutoUpdateHelper.cs 2025-06-24 16:53:49 +08:00
Hydrogen b21e608eea 增加dc链接
不知怎么回事,dc的在线人数显示不出来(从aiwb inkways的dc标签修改而来)
2025-06-23 15:01:42 +08:00
Hydrogen 671ec2fba6 更新 README 文件,加入贡献指南
在自述文件中添加了一个新部分,提供贡献指南,包括提交代码到测试分支的说明。同时作为构建过程的一部分,更新了生成的文件和缓存文件。
(标题和介绍由Copilot生成并使用巨硬机翻)
2025-06-23 14:48:35 +08:00
Hydrogen 293a89575a 更新README
将新readme同步到beta

Co-Authored-By: DotteringDoge471 <185512682+DotteringDoge471@users.noreply.github.com>
2025-06-23 14:37:33 +08:00
Hydrogen 542812eb74 初步添加重启计数器
1. 防止异常重启死循环
2. 为未来可能的新功能做准备
2025-06-23 14:33:58 +08:00
DotteringDoge471 e44cb715d0 fix(docs): typo. 2025-06-23 02:46:33 +08:00
DotteringDoge471 f7a1a1c851 feat(docs): 更新了README.md。 2025-06-23 02:44:17 +08:00
CJKmkp 757c08cd02 improve:UI改进 2025-06-20 13:51:18 +08:00
CJKmkp 15fcd50151 improve:改进多指触摸操作 2025-06-20 11:23:57 +08:00
CJKmkp 867a747853 improve:改进多指触摸操作 2025-06-19 22:49:11 +08:00
CJKmkp 02dfbb54b6 fix:灵敏度阈值范围过小导致的调节无效 2025-06-19 15:12:40 +08:00
CJK_mkp c42c6c8dfe Merge pull request #37 from awesome-iwb/beta
ICC CE 1.6.7 (ICC CE Beta 1.6.14)
2025-06-19 14:38:19 +08:00
CJKmkp 316d568cbc 更新版本号 2025-06-19 14:33:01 +08:00
CJKmkp 0b72b1f1b3 fix:设置窗口关闭导致的无法点击 2025-06-19 14:32:16 +08:00
CJKmkp 25b52def92 fix:直线拉直及端点吸附 2025-06-19 14:30:24 +08:00
CJK_mkp ab67ea48f0 Merge pull request #36 from awesome-iwb/beta
ICC CE 1.6.6 (ICC CE Beta 1.6.13)
2025-06-19 12:00:20 +08:00
CJK_mkp 912c1b91e4 更新版本号 2025-06-19 11:56:36 +08:00
CJK_mkp d4f1d21634 improve:静默更新 2025-06-19 11:47:16 +08:00
CJK_mkp 6c0e7c2e64 fix:触屏类问题及设置内点击问题 2025-06-19 11:25:15 +08:00
CJK_mkp e054a50b55 Merge pull request #35 from awesome-iwb/beta
Update AutomaticUpdateVersionControl.txt
2025-06-18 23:09:27 +08:00
CJK_mkp ff005e6398 Update AutomaticUpdateVersionControl.txt 2025-06-18 23:08:47 +08:00
CJK_mkp 74cc8e7dda Merge pull request #34 from awesome-iwb/beta
修改版本号
2025-06-18 22:59:52 +08:00
CJK_mkp 254d70a787 修改版本号 2025-06-18 22:58:18 +08:00
CJK_mkp 28b728822c Merge pull request #33 from awesome-iwb/beta
ICC CE 1.6.4(ICC CE Beta1.6.8)
2025-06-18 22:44:30 +08:00
CJK_mkp 5a53471bcd improve:自动更新 2025-06-18 22:42:21 +08:00
CJK_mkp a3fee5d77c improve:自动更新 2025-06-18 22:40:48 +08:00
CJK_mkp 6f961225d7 更新版本号 2025-06-18 22:29:28 +08:00
CJK_mkp 1b0b4f7505 去除了miku 2025-06-18 22:19:34 +08:00
CJK_mkp fac66fafbd fix:墨迹压感问题 2025-06-18 18:31:03 +08:00
CJK_mkp b9d6ac3047 Merge pull request #32 from awesome-iwb/beta
ICC CE 1.6.4(ICC CE Beta1.6.7)
2025-06-18 18:20:56 +08:00
CJK_mkp e7c723de46 fix:进程崩溃判定错误 improve:重新配置了自动更新 2025-06-18 18:16:48 +08:00
CJK_mkp 10629b253c 修复自动更新 2025-06-18 16:12:47 +08:00
CJK_mkp dace6ad486 修改自动更新 2025-06-18 16:08:26 +08:00
CJK_mkp 4c70f35714 Merge pull request #31 from awesome-iwb/beta
ICC CE 1.6.3 (ICC CE Beta1.6.6)
2025-06-18 15:44:17 +08:00
CJK_mkp 7b4d13c16f update:自动更新服务 2025-06-18 15:40:07 +08:00
CJK_mkp 0e561ad24e 修改版本 2025-06-18 15:32:45 +08:00
CJK_mkp d09d8223c9 更新版本号 2025-06-18 15:12:44 +08:00
CJK_mkp 6dafde9735 improve:直线拉直灵敏度设置 2025-06-18 15:10:33 +08:00
CJK_mkp a0f84bf017 Merge pull request #30 from awesome-iwb/beta
ICC CE 1.6.2 (ICC CE Beta  1.6.4)
2025-06-18 13:42:52 +08:00
CJK_mkp 7049c53889 fix:墨迹纠正 2025-06-18 13:37:52 +08:00
CJK_mkp 7750fa799d fix:墨迹纠正 2025-06-18 13:24:50 +08:00
CJK_mkp 5f828736de fix:issue #13 #23 add:设置页面侧边栏 2025-06-18 09:08:38 +08:00
CJK_mkp 869c8ce31b Merge pull request #29 from awesome-iwb/beta
ICC CE 1.6.1 (Beta 1.6.1)
2025-06-17 22:38:48 +08:00
CJK_mkp 0b7b55224f add:直线拉直与端点吸附 2025-06-17 22:37:37 +08:00
CJK_mkp 2a23be44f2 add:有关触屏体验改进的功能 2025-06-17 22:05:22 +08:00
CJK_mkp fa0cbb4d3f fix:修复日志重复输出 2025-06-17 21:45:50 +08:00
CJK_mkp 38bc4decf6 fix:issue #13 #23 2025-06-17 21:24:47 +08:00
CJK_mkp b5ec6e0d79 Merge pull request #28 from awesome-iwb/beta
ICC CE 1.5.2 (Beta 1.5.14)
2025-06-17 19:22:32 +08:00
CJK_mkp 82486c707d fix:issue #5 2025-06-17 19:15:22 +08:00
CJK_mkp 5ff437bed5 improve:PPT联动 2025-06-17 19:09:31 +08:00
CJK_mkp 2f7e0b85c0 fix:issue #3 2025-06-17 19:00:47 +08:00
CJK_mkp c9548af008 fix:issue #3 2025-06-17 18:52:34 +08:00
CJK_mkp b20e4a041f fix:issue #13 #23 2025-06-17 18:45:55 +08:00
CJK_mkp 87f64ccc81 improve:对随机抽功能增加禁用开关 2025-06-17 18:21:14 +08:00
CJK_mkp 58028ea95c fix:issue #13 #23 2025-06-17 13:20:06 +08:00
CJK_mkp 35fa062cc3 improve:尝试使用注册表方法禁用受保护的视图功能(不确定可用性) 2025-06-13 13:44:50 +08:00
CJK_mkp 9de6555519 fix:issue #13 #23 2025-06-13 11:43:50 +08:00
CJK_mkp a9baf47823 fix:修复崩溃自动重启的误判 2025-06-13 09:19:44 +08:00
CJK_mkp a9b64d2899 fix:issue #3 2025-06-12 22:48:25 +08:00
CJK_mkp 4d9fa754e8 Merge pull request #26 from awesome-iwb/beta
ICC CE 1.5.1 (Bate1.5.5)
2025-06-12 19:19:18 +08:00
CJK_mkp 862ac27212 fix:issue #13 #23 2025-06-12 19:14:58 +08:00
CJK_mkp 4ada8b05e7 fix:只读状态下翻页控件无法使用 2025-06-12 18:55:50 +08:00
CJK_mkp d250e83df9 fix:只读状态下无法识别的问题 2025-06-12 14:26:01 +08:00
CJK_mkp 8e8f4256ac fix:issue #13 #23 2025-06-12 11:23:59 +08:00
CJK_mkp d6502251e1 fix:issue #13 #23 2025-06-12 11:21:45 +08:00
CJK_mkp c3159c61ee improve:优化进程崩溃检测机制 2025-06-12 10:34:29 +08:00
CJK_mkp 0e5b31a8e4 add:崩溃后操作 2025-06-12 10:13:47 +08:00
555 changed files with 59962 additions and 150974 deletions
+94
View File
@@ -0,0 +1,94 @@
{
"projectName": "community",
"projectOwner": "InkCanvasForClass",
"files": [
"README.md"
],
"commitType": "docs",
"commitConvention": "angular",
"contributorsPerLine": 7,
"contributors": [
{
"login": "CJKmkp",
"name": "CJK_mkp",
"avatar_url": "https://avatars.githubusercontent.com/u/113243675?v=4",
"profile": "https://github.com/CJKmkp",
"contributions": [
"maintenance",
"doc",
"code"
]
},
{
"login": "CreeperAWA",
"name": "CreeperAWA",
"avatar_url": "https://avatars.githubusercontent.com/u/134939494?v=4",
"profile": "https://github.com/CreeperAWA",
"contributions": [
"code"
]
},
{
"login": "2-2-3-trimethylpentane",
"name": "2,2,3-三甲基戊烷",
"avatar_url": "https://avatars.githubusercontent.com/u/141403762?v=4",
"profile": "https://github.com/2-2-3-trimethylpentane",
"contributions": [
"blog",
"doc",
"design"
]
},
{
"login": "Alan-CRL",
"name": "Alan-CRL",
"avatar_url": "https://avatars.githubusercontent.com/u/92425617?v=4",
"profile": "https://github.com/Alan-CRL",
"contributions": [
"code",
"infra",
"doc",
"financial"
]
},
{
"login": "MKStoler1024",
"name": "MKStoler1024",
"avatar_url": "https://avatars.githubusercontent.com/u/158786854?v=4",
"profile": "https://github.com/MKStoler1024",
"contributions": [
"doc",
"code",
"design"
]
},
{
"login": "awesome-iwb",
"name": "Awesome Iwb",
"avatar_url": "https://avatars.githubusercontent.com/u/184760810?v=4",
"profile": "https://github.com/awesome-iwb",
"contributions": [
"doc"
]
},
{
"login": "PrefacedCorg",
"name": "PrefacedCorg",
"avatar_url": "https://avatars.githubusercontent.com/u/129855423?v=4",
"profile": "https://github.com/PrefacedCorg",
"contributions": [
"code",
"design"
]
},
{
"login": "Jursin",
"name": "Jursin",
"avatar_url": "https://avatars.githubusercontent.com/u/127487914?v=4",
"profile": "http://blog.jursin.top",
"contributions": [
"design"
]
}
]
}
-22
View File
@@ -1,22 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
## Description
## Reproduction
## Expected behavior
## Screenshots
## Additional context
+56
View File
@@ -0,0 +1,56 @@
name: Bug 报告 | Bug Report
description: 反馈软件缺陷或异常 | Report a bug to help us improve
labels: [bug]
body:
- type: markdown
attributes:
value: |
感谢你的反馈!请详细填写以下内容,便于我们定位问题。
Thank you for your feedback! Please fill out the following information to help us locate the issue.
- type: input
id: version
attributes:
label: 软件版本 | App Version
description: 可在设置中的“关于”界面查看 | You can find it on the "About" interface in the settings
placeholder: 例如 v1.2.3 | e.g. v1.2.3
validations:
required: true
- type: input
id: os
attributes:
label: 操作系统及版本 | OS & Version
placeholder: 例如 Windows 10 22H2 64位 | e.g. Windows 10 22H2 64bit
validations:
required: true
- type: textarea
id: description
attributes:
label: 问题描述 | Description
description: 简要描述遇到的问题 | Briefly describe the problem
validations:
required: true
- type: textarea
id: steps
attributes:
label: 复现步骤 | Steps to Reproduce
description: 如何复现该问题?如有必要可附截图/录屏 | How to reproduce this bug? Screenshots/recordings if needed
placeholder: |
1.
2.
3.
validations:
required: true
- type: textarea
id: expected
attributes:
label: 期望结果 | Expected Behavior
description: 你期望的正确行为或结果 | What did you expect to happen?
validations:
required: true
- type: textarea
id: extra
attributes:
label: 其他补充信息 | Additional Info
description: 其他相关信息(如日志、配置、特殊环境等)| Any other context, logs, configs, special environment, etc.
validations:
required: false
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
-10
View File
@@ -1,10 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
## Description
@@ -0,0 +1,37 @@
name: 功能请求 | Feature Request
description: 提出你对本项目的功能建议 | Suggest an idea for this project
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
感谢你的建议!请详细描述你的需求。
Thank you for your suggestion! Please describe your needs in detail.
- type: textarea
id: description
attributes:
label: 功能描述 | Description
description: 请描述你希望添加的功能 | Describe the feature you want
validations:
required: true
- type: textarea
id: motivation
attributes:
label: 需求动机 | Motivation
description: 为什么需要这个功能?| Why do you need this feature?
validations:
required: true
- type: textarea
id: design
attributes:
label: 期望设计 | Expected Design
description: (可选)描述或画出你期望的界面或交互 | (Optional) Describe or sketch the expected UI/UX
validations:
required: false
- type: textarea
id: extra
attributes:
label: 其他补充信息 | Additional Info
description: 其他补充说明或建议 | Any other context or suggestions
validations:
required: false
+2 -2
View File
@@ -26,10 +26,10 @@ jobs:
- name: Build the Solution
run: |
msbuild -t:restore /p:GitFlow="Github Action"
msbuild /p:platform="Any CPU" /p:configuration="Release" /p:GitFlow="Github Action" "Ink Canvas/InkCanvasForClass.csproj"
msbuild /p:platform="AnyCPU" /p:configuration="Debug" /p:GitFlow="Github Action" "Ink Canvas/InkCanvasForClass.csproj"
- name: Upload to artifact
uses: actions/upload-artifact@v4.5.0
with:
name: InkCanvasForClass
path: "Ink Canvas/bin/Any CPU/Release/net472/"
path: "Ink Canvas/bin/Debug/net472"
+4 -3
View File
@@ -1,3 +1,4 @@
/Ink Canvas/obj
/Ink Canvas/bin
/.vs
obj/
bin/
.vs/
/Ink Canvas/obj
+1
View File
@@ -2,5 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../alpha" vcs="Git" />
</component>
</project>
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,183 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow_cs\\mw_floatingbaricons.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow_cs\\mw_floatingbaricons.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:privacy.txt||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Manual.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:LICENSE||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Ink Canvas.sln.DotSettings.user||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
},
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow_cs\\mw_ppt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow_cs\\mw_ppt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "MW_FloatingBarIcons.cs",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs*",
"RelativeToolTip": "Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs*",
"ViewState": "AgIAAFgHAAAAAAAAAAAgwGcHAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-05-31T10:49:24.719Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "README.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md",
"RelativeDocumentMoniker": "README.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md",
"RelativeToolTip": "README.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-31T10:48:22.883Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "MainWindow.xaml",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow.xaml",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow.xaml",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow.xaml",
"RelativeToolTip": "Ink Canvas\\MainWindow.xaml",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|",
"WhenOpened": "2025-05-24T13:22:56.715Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "Microsoft.Common.CurrentVersion.targets",
"DocumentMoniker": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"RelativeDocumentMoniker": "..\\..\\..\\..\\..\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"ToolTip": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"RelativeToolTip": "..\\..\\..\\..\\..\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"ViewState": "AgIAAGsJAAAAAAAAAAAQwIEJAAAEAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003801|",
"WhenOpened": "2025-05-24T13:06:01.053Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "MW_PPT.cs",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"RelativeToolTip": "Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"ViewState": "AgIAAFgAAAAAAAAAAAAUwHQAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-05-24T13:04:47.205Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "README.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md",
"RelativeDocumentMoniker": "..\\icc-0610.2.3\\README.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md",
"RelativeToolTip": "..\\icc-0610.2.3\\README.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-24T13:04:01.407Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "privacy.txt",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt",
"RelativeDocumentMoniker": "privacy.txt",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt",
"RelativeToolTip": "privacy.txt",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003109|",
"WhenOpened": "2025-05-24T13:04:01.337Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "Manual.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md",
"RelativeDocumentMoniker": "Manual.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md",
"RelativeToolTip": "Manual.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-24T13:04:00.986Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "LICENSE",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE",
"RelativeDocumentMoniker": "LICENSE",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE",
"RelativeToolTip": "LICENSE",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-05-24T13:04:00.902Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "Ink Canvas.sln.DotSettings.user",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user",
"RelativeDocumentMoniker": "Ink Canvas.sln.DotSettings.user",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user",
"RelativeToolTip": "Ink Canvas.sln.DotSettings.user",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003464|",
"WhenOpened": "2025-05-24T13:04:00.792Z",
"EditorCaption": ""
}
]
}
]
}
]
}
-183
View File
@@ -1,183 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow_cs\\mw_floatingbaricons.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow_cs\\mw_floatingbaricons.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:privacy.txt||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Manual.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:LICENSE||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user||{FA3CD31E-987B-443A-9B81-186104E8DAC1}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:Ink Canvas.sln.DotSettings.user||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
},
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow_cs\\mw_ppt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow_cs\\mw_ppt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|c:\\users\\administrator\\desktop\\icc ce\\icc ce 1.2.5\\ink canvas\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}",
"RelativeMoniker": "D:0:0:{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}|Ink Canvas\\InkCanvasForClass.csproj|solutionrelative:ink canvas\\mainwindow.xaml||{F11ACC28-31D1-4C80-A34B-F4E09D3D753C}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md||{EFC0BB08-EA7D-40C6-A696-C870411A895B}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets||{FA3CD31E-987B-443A-9B81-186104E8DAC1}|"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "MW_FloatingBarIcons.cs",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"RelativeToolTip": "Ink Canvas\\MainWindow_cs\\MW_FloatingBarIcons.cs",
"ViewState": "AgIAAFgHAAAAAAAAAAAgwGcHAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-05-31T10:49:24.719Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "README.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md",
"RelativeDocumentMoniker": "README.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\README.md",
"RelativeToolTip": "README.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-31T10:48:22.883Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "MainWindow.xaml",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow.xaml",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow.xaml",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow.xaml",
"RelativeToolTip": "Ink Canvas\\MainWindow.xaml",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003549|",
"WhenOpened": "2025-05-24T13:22:56.715Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "Microsoft.Common.CurrentVersion.targets",
"DocumentMoniker": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"RelativeDocumentMoniker": "..\\..\\..\\..\\..\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"ToolTip": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"RelativeToolTip": "..\\..\\..\\..\\..\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\amd64\\Microsoft.Common.CurrentVersion.targets",
"ViewState": "AgIAAGsJAAAAAAAAAAAQwIEJAAAEAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003801|",
"WhenOpened": "2025-05-24T13:06:01.053Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "MW_PPT.cs",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"RelativeDocumentMoniker": "Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"RelativeToolTip": "Ink Canvas\\MainWindow_cs\\MW_PPT.cs",
"ViewState": "AgIAAFgAAAAAAAAAAAAUwHQAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-05-24T13:04:47.205Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "README.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md",
"RelativeDocumentMoniker": "..\\icc-0610.2.3\\README.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\README.md",
"RelativeToolTip": "..\\icc-0610.2.3\\README.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-24T13:04:01.407Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "privacy.txt",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt",
"RelativeDocumentMoniker": "privacy.txt",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\privacy.txt",
"RelativeToolTip": "privacy.txt",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003109|",
"WhenOpened": "2025-05-24T13:04:01.337Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "Manual.md",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md",
"RelativeDocumentMoniker": "Manual.md",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Manual.md",
"RelativeToolTip": "Manual.md",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001818|",
"WhenOpened": "2025-05-24T13:04:00.986Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "LICENSE",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE",
"RelativeDocumentMoniker": "LICENSE",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\LICENSE",
"RelativeToolTip": "LICENSE",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-05-24T13:04:00.902Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "Ink Canvas.sln.DotSettings.user",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user",
"RelativeDocumentMoniker": "Ink Canvas.sln.DotSettings.user",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\ICC CE 1.2.5\\Ink Canvas.sln.DotSettings.user",
"RelativeToolTip": "Ink Canvas.sln.DotSettings.user",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003464|",
"WhenOpened": "2025-05-24T13:04:00.792Z",
"EditorCaption": ""
}
]
}
]
}
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}
Binary file not shown.
@@ -1,290 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "System.ValueTuple.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\System.ValueTuple.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\System.ValueTuple.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:48.138Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Settings.json",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Settings.json",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Settings.json",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
"WhenOpened": "2025-05-24T13:02:44.878Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "OSVersionExt.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\OSVersionExt.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\OSVersionExt.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.837Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "Office.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Office.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Office.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.774Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "NHotkey.Wpf.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\NHotkey.Wpf.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\NHotkey.Wpf.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.718Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "NHotkey.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\NHotkey.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\NHotkey.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.662Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "Newtonsoft.Json.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Newtonsoft.Json.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Newtonsoft.Json.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.589Z"
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "Microsoft.Office.Interop.PowerPoint.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.932Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "MdXaml.Plugins.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\MdXaml.Plugins.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\MdXaml.Plugins.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.838Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "MdXaml.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\MdXaml.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\MdXaml.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.776Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "iNKORE.UI.WPF.Modern.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.573Z"
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "iNKORE.UI.WPF.Modern.Controls.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.432Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "iNKORE.UI.WPF.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:42.807Z"
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "InkCanvasForClass.exe.config",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000601|",
"WhenOpened": "2025-05-24T13:02:27.288Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "ICSharpCode.AvalonEdit.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.847Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "IAWinFX.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IAWinFX.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IAWinFX.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.816Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "IALoader.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IALoader.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IALoader.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.784Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "IACore.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IACore.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IACore.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.753Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "Hardcodet.NotifyIcon.Wpf.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.113Z"
}
]
}
]
}
]
}
-338
View File
@@ -1,338 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config||{FA3CD31E-987B-443A-9B81-186104E8DAC1}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll||{177559E0-D141-11D0-92DF-00A0C9138C45}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "icc.png - PNG [256x256, 32 \u4F4D, PNG]",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\icc.png",
"RelativeDocumentMoniker": "icc.png",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\icc.png - PNG [256x256, 32 \u4F4D, PNG]",
"RelativeToolTip": "icc.png - PNG [256x256, 32 \u4F4D, PNG]",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
"WhenOpened": "2025-05-24T13:03:45.63Z",
"EditorCaption": " - PNG [256x256, 32 \u4F4D, PNG]"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "AutomaticUpdateVersionControl.txt",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\AutomaticUpdateVersionControl.txt",
"RelativeDocumentMoniker": "AutomaticUpdateVersionControl.txt",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\AutomaticUpdateVersionControl.txt",
"RelativeToolTip": "AutomaticUpdateVersionControl.txt",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003109|",
"WhenOpened": "2025-05-24T13:03:45.517Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": ".gitignore",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\.gitignore",
"RelativeDocumentMoniker": ".gitignore",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.2\\.gitignore",
"RelativeToolTip": ".gitignore",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-05-24T13:03:43.13Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "System.ValueTuple.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\System.ValueTuple.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\System.ValueTuple.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\System.ValueTuple.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:48.138Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "Settings.json",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Settings.json",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Settings.json",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Settings.json",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
"WhenOpened": "2025-05-24T13:02:44.878Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "OSVersionExt.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\OSVersionExt.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\OSVersionExt.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\OSVersionExt.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.837Z"
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "Office.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Office.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Office.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Office.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.774Z"
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "NHotkey.Wpf.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\NHotkey.Wpf.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.Wpf.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\NHotkey.Wpf.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.718Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "NHotkey.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\NHotkey.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\NHotkey.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\NHotkey.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.662Z"
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "Newtonsoft.Json.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Newtonsoft.Json.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Newtonsoft.Json.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Newtonsoft.Json.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:44.589Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"Title": "Microsoft.Office.Interop.PowerPoint.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Microsoft.Office.Interop.PowerPoint.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.932Z"
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "MdXaml.Plugins.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\MdXaml.Plugins.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.Plugins.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\MdXaml.Plugins.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.838Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "MdXaml.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\MdXaml.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\MdXaml.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\MdXaml.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.776Z"
},
{
"$type": "Document",
"DocumentIndex": 13,
"Title": "iNKORE.UI.WPF.Modern.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.573Z"
},
{
"$type": "Document",
"DocumentIndex": 14,
"Title": "iNKORE.UI.WPF.Modern.Controls.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.Modern.Controls.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:43.432Z"
},
{
"$type": "Document",
"DocumentIndex": 15,
"Title": "iNKORE.UI.WPF.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\iNKORE.UI.WPF.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:42.807Z"
},
{
"$type": "Document",
"DocumentIndex": 16,
"Title": "InkCanvasForClass.exe.config",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\InkCanvasForClass.exe.config",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000601|",
"WhenOpened": "2025-05-24T13:02:27.288Z"
},
{
"$type": "Document",
"DocumentIndex": 17,
"Title": "ICSharpCode.AvalonEdit.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\ICSharpCode.AvalonEdit.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.847Z"
},
{
"$type": "Document",
"DocumentIndex": 18,
"Title": "IAWinFX.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IAWinFX.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IAWinFX.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IAWinFX.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.816Z"
},
{
"$type": "Document",
"DocumentIndex": 19,
"Title": "IALoader.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IALoader.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IALoader.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IALoader.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.784Z"
},
{
"$type": "Document",
"DocumentIndex": 20,
"Title": "IACore.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\IACore.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\IACore.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\IACore.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.753Z"
},
{
"$type": "Document",
"DocumentIndex": 21,
"Title": "Hardcodet.NotifyIcon.Wpf.dll",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"RelativeDocumentMoniker": "..\\..\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"RelativeToolTip": "..\\..\\InkCanvasForClass\\Hardcodet.NotifyIcon.Wpf.dll",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001697|",
"WhenOpened": "2025-05-24T13:02:22.113Z"
}
]
}
]
}
]
}
Binary file not shown.
Binary file not shown.
@@ -1,67 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 0,
"Children": [
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "icc.png",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png",
"RelativeDocumentMoniker": "icc.png",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png",
"RelativeToolTip": "icc.png",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
"WhenOpened": "2025-05-24T13:12:49.619Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "AutomaticUpdateVersionControl.txt",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt",
"RelativeDocumentMoniker": "AutomaticUpdateVersionControl.txt",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt",
"RelativeToolTip": "AutomaticUpdateVersionControl.txt",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003109|",
"WhenOpened": "2025-05-24T13:12:49.575Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": ".gitignore",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore",
"RelativeDocumentMoniker": ".gitignore",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore",
"RelativeToolTip": ".gitignore",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-05-24T13:12:49.025Z"
}
]
}
]
}
]
}
-72
View File
@@ -1,72 +0,0 @@
{
"Version": 1,
"WorkspaceRootPath": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:icc.png||{177559E0-D141-11D0-92DF-00A0C9138C45}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:AutomaticUpdateVersionControl.txt||{8B382828-6202-11D1-8870-0000F87579D2}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:.gitignore||{3B902123-F8A7-4915-9F01-361F908088D0}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 1,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "icc.png - PNG [1328x1328, 32 \u4F4D, PNG]",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png",
"RelativeDocumentMoniker": "icc.png",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\icc.png - PNG [1328x1328, 32 \u4F4D, PNG]",
"RelativeToolTip": "icc.png - PNG [1328x1328, 32 \u4F4D, PNG]",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001533|",
"WhenOpened": "2025-05-24T13:12:49.619Z",
"EditorCaption": " - PNG [1328x1328, 32 \u4F4D, PNG]"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "AutomaticUpdateVersionControl.txt",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt",
"RelativeDocumentMoniker": "AutomaticUpdateVersionControl.txt",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\AutomaticUpdateVersionControl.txt",
"RelativeToolTip": "AutomaticUpdateVersionControl.txt",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003109|",
"WhenOpened": "2025-05-24T13:12:49.575Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": ".gitignore",
"DocumentMoniker": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore",
"RelativeDocumentMoniker": ".gitignore",
"ToolTip": "C:\\Users\\Administrator\\Desktop\\ICC CE\\icc-0610.2.3\\.gitignore",
"RelativeToolTip": ".gitignore",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-05-24T13:12:49.025Z"
}
]
}
]
}
]
}
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
1.4.7
1.7.12.0
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

+5 -1
View File
@@ -1,2 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">WARNING</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/PencilsConfiguration/ActualSeverity/@EntryValue">WARNING</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe</s:String>
<s:Int64 x:Key="/Default/Environment/Hierarchy/Build/BuildTool/MsbuildVersion/@EntryValue">1114112</s:Int64>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=InkCanvasForClass_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>
File diff suppressed because one or more lines are too long
+3 -4
View File
@@ -4,13 +4,13 @@
xmlns:local="clr-namespace:Ink_Canvas"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
StartupUri="MainWindow.xaml">
>
<Application.Resources>
<ResourceDictionary>
<Style TargetType="ui:ScrollViewerEx">
<EventSetter Event="PreviewMouseWheel" Handler="ScrollViewer_PreviewMouseWheel"/>
</Style>
<ContextMenu Opened="SysTrayMenu_Opened" x:Shared="false" x:Key="SysTrayMenu" Padding="6" ui:ThemeManager.RequestedTheme="Light">
<ContextMenu Opened="SysTrayMenu_Opened" Closed="SysTrayMenu_Closed" x:Shared="false" x:Key="SysTrayMenu" Padding="6" ui:ThemeManager.RequestedTheme="Light">
<MenuItem IsCheckable="True" IsChecked="False" Checked="HideICCMainWindowTrayIconMenuItem_Checked" Unchecked="HideICCMainWindowTrayIconMenuItem_UnChecked" Name="HideICCMainWindowTrayIconMenuItem">
<MenuItem.Header>
<ui:SimpleStackPanel Orientation="Horizontal" Margin="-4,0,0,0">
@@ -32,7 +32,7 @@
</MenuItem.Icon>
</MenuItem>
<Separator Margin="0,3" />
<MenuItem>
<MenuItem Name="DisableAllHotkeysMenuItem" Click="DisableAllHotkeysMenuItem_Clicked">
<MenuItem.Header>
<ui:SimpleStackPanel Orientation="Horizontal" Margin="-4,0,0,0">
<TextBlock FontSize="14" VerticalAlignment="Center" Foreground="#18181b" Text="禁用所有快捷键" />
@@ -237,7 +237,6 @@
<ResourceDictionary Source="Resources/SeewoImageDictionary.xaml"/>
<ResourceDictionary Source="Resources/DrawShapeImageDictionary.xaml"/>
<ResourceDictionary Source="Resources/IconImageDictionary.xaml"/>
<ResourceDictionary Source="Resources/Styles/Light.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
+1063 -26
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,4 +1,4 @@
using System.Reflection;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
@@ -8,7 +8,7 @@ using System.Windows;
[assembly: AssemblyTitle("InkCanvasForClass")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Dubi906w")]
[assembly: AssemblyCompany("CJK_mkp")]
[assembly: AssemblyProduct("InkCanvasForClass")]
[assembly: AssemblyCopyright("Copyright © HARKOTEK Studio 2024")]
[assembly: AssemblyTrademark("")]
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.0.2.0")]
[assembly: AssemblyFileVersion("5.0.2.0")]
[assembly: AssemblyVersion("1.7.12.0")]
[assembly: AssemblyFileVersion("1.7.12.0")]
@@ -0,0 +1,398 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
/// <summary>
/// 悬浮窗拦截管理器
/// </summary>
public class FloatingWindowInterceptorManager : IDisposable
{
#region
private FloatingWindowInterceptor _interceptor;
private bool _isInitialized;
private bool _disposed;
private FloatingWindowInterceptorSettings _settings;
#endregion
#region
public event EventHandler<FloatingWindowInterceptor.WindowInterceptedEventArgs> WindowIntercepted;
public event EventHandler<FloatingWindowInterceptor.WindowRestoredEventArgs> WindowRestored;
#endregion
#region
public bool IsEnabled => _interceptor != null && _settings != null && _settings.IsEnabled;
public bool IsRunning => _interceptor != null && _interceptor.IsRunning;
#endregion
#region
/// <summary>
/// 初始化拦截器
/// </summary>
public void Initialize(FloatingWindowInterceptorSettings settings)
{
if (_isInitialized) return;
try
{
_settings = settings ?? new FloatingWindowInterceptorSettings();
_interceptor = new FloatingWindowInterceptor();
// 订阅事件
_interceptor.WindowIntercepted += OnWindowIntercepted;
_interceptor.WindowRestored += OnWindowRestored;
// 应用配置
ApplySettings();
_isInitialized = true;
// 如果设置了自动启动,则启动拦截器
if (_settings.AutoStart && _settings.IsEnabled)
{
Start();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 启动拦截器
/// </summary>
public void Start()
{
if (!_isInitialized || _settings == null) return;
if (_interceptor == null) return;
try
{
_interceptor.Start(_settings.ScanIntervalMs);
LogHelper.WriteLogToFile("悬浮窗拦截器已启动", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 停止拦截器
/// </summary>
public void Stop()
{
if (_interceptor == null) return;
try
{
_interceptor.Stop();
LogHelper.WriteLogToFile("悬浮窗拦截器已停止", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"停止悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 设置拦截规则
/// </summary>
public void SetInterceptRule(FloatingWindowInterceptor.InterceptType type, bool enabled)
{
if (_interceptor == null || _settings == null) return;
try
{
_interceptor.SetInterceptRule(type, enabled);
// 更新设置
var ruleName = type.ToString();
if (_settings.InterceptRules.ContainsKey(ruleName))
{
_settings.InterceptRules[ruleName] = enabled;
}
// 获取规则信息以处理父子关系
var rule = _interceptor.GetInterceptRule(type);
if (rule != null)
{
// 如果是父规则,更新所有子规则的设置
if (rule.ChildTypes.Count > 0)
{
foreach (var childType in rule.ChildTypes)
{
var childRuleName = childType.ToString();
if (_settings.InterceptRules.ContainsKey(childRuleName))
{
_settings.InterceptRules[childRuleName] = enabled;
}
}
}
// 如果是子规则,更新父规则的设置
else if (rule.ParentType.HasValue)
{
var parentRule = _interceptor.GetInterceptRule(rule.ParentType.Value);
if (parentRule != null)
{
var parentRuleName = rule.ParentType.Value.ToString();
if (_settings.InterceptRules.ContainsKey(parentRuleName))
{
_settings.InterceptRules[parentRuleName] = parentRule.IsEnabled;
}
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置拦截规则失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 获取拦截规则
/// </summary>
public FloatingWindowInterceptor.InterceptRule GetInterceptRule(FloatingWindowInterceptor.InterceptType type)
{
return _interceptor?.GetInterceptRule(type);
}
/// <summary>
/// 获取所有拦截规则
/// </summary>
public Dictionary<FloatingWindowInterceptor.InterceptType, FloatingWindowInterceptor.InterceptRule> GetAllRules()
{
return _interceptor?.GetAllRules() ?? new Dictionary<FloatingWindowInterceptor.InterceptType, FloatingWindowInterceptor.InterceptRule>();
}
/// <summary>
/// 手动扫描一次
/// </summary>
public void ScanOnce()
{
if (_interceptor == null) return;
try
{
_interceptor.ScanOnce();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"手动扫描失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 恢复所有被拦截的窗口
/// </summary>
public void RestoreAllWindows()
{
if (_interceptor == null) return;
try
{
_interceptor.RestoreAllWindows();
LogHelper.WriteLogToFile("已恢复所有被拦截的窗口", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"恢复窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 应用设置
/// </summary>
public void ApplySettings()
{
if (_interceptor == null || _settings == null) return;
try
{
// 应用拦截规则设置
foreach (var kvp in _settings.InterceptRules)
{
if (Enum.TryParse<FloatingWindowInterceptor.InterceptType>(kvp.Key, out var type))
{
_interceptor.SetInterceptRule(type, kvp.Value);
}
}
// 如果启用了拦截器,则启动
if (_settings.IsEnabled && !IsRunning)
{
Start();
}
// 如果禁用了拦截器,则停止
else if (!_settings.IsEnabled && IsRunning)
{
Stop();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用设置失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 更新扫描间隔
/// </summary>
public void UpdateScanInterval(int intervalMs)
{
if (_interceptor == null || _settings == null) return;
try
{
_settings.ScanIntervalMs = intervalMs;
// 如果正在运行,重启以应用新间隔
if (IsRunning)
{
Stop();
Start();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新扫描间隔失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 获取拦截统计信息
/// </summary>
public InterceptStatistics GetStatistics()
{
if (_interceptor == null || _settings == null) return new InterceptStatistics();
try
{
var rules = GetAllRules();
var enabledRules = rules.Count(r => r.Value.IsEnabled);
var totalRules = rules.Count;
return new InterceptStatistics
{
TotalRules = totalRules,
EnabledRules = enabledRules,
IsRunning = IsRunning,
ScanIntervalMs = _settings.ScanIntervalMs
};
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取统计信息失败: {ex.Message}", LogHelper.LogType.Error);
return new InterceptStatistics();
}
}
#endregion
#region
private void OnWindowIntercepted(object sender, FloatingWindowInterceptor.WindowInterceptedEventArgs e)
{
try
{
// 记录日志
LogHelper.WriteLogToFile($"拦截窗口: {e.WindowTitle} ({e.InterceptType})", LogHelper.LogType.Event);
// 显示通知(如果启用)
if (_settings != null && _settings.ShowNotifications)
{
ShowNotification($"已拦截悬浮窗: {e.Rule.Description}");
}
// 触发事件
WindowIntercepted?.Invoke(this, e);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口拦截事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void OnWindowRestored(object sender, FloatingWindowInterceptor.WindowRestoredEventArgs e)
{
try
{
// 记录日志
LogHelper.WriteLogToFile($"恢复窗口: {e.InterceptType}", LogHelper.LogType.Event);
// 触发事件
WindowRestored?.Invoke(this, e);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口恢复事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void ShowNotification(string message)
{
try
{
// 这里可以集成系统通知或自定义通知
// 暂时使用调试输出
System.Diagnostics.Debug.WriteLine($"通知: {message}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示通知失败: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
public class InterceptStatistics
{
public int TotalRules { get; set; }
public int EnabledRules { get; set; }
public bool IsRunning { get; set; }
public int ScanIntervalMs { get; set; }
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
try
{
Stop();
_interceptor?.Dispose();
_interceptor = null;
_isInitialized = false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
finally
{
_disposed = true;
}
}
#endregion
}
}
+3
View File
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura ExcludeAssemblies="IACore|IALoader|IAWinFX" />
</Weavers>
+176
View File
@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableEventSubscription" type="xs:boolean">
<xs:annotation>
<xs:documentation>The attach method no longer subscribes to the `AppDomain.AssemblyResolve` (.NET 4.x) and `AssemblyLoadContext.Resolving` (.NET 6.0+) events.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
File diff suppressed because it is too large Load Diff
+216
View File
@@ -0,0 +1,216 @@
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Linq;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 自动备份管理器
/// 负责管理配置文件的自动备份功能
/// </summary>
public static class AutoBackupManager
{
private static readonly string BackupDir = Path.Combine(App.RootPath, "Backups");
private static readonly string SettingsFile = Path.Combine(App.RootPath, "Configs", "Settings.json");
private static readonly string BackupPrefix = "Settings_AutoBackup_";
/// <summary>
/// 检查是否需要执行自动备份
/// </summary>
/// <param name="settings">设置对象</param>
/// <returns>如果需要备份返回true,否则返回false</returns>
public static bool ShouldPerformAutoBackup(Settings settings)
{
try
{
// 如果自动备份功能未启用,不执行备份
if (!settings.Advanced.IsAutoBackupEnabled)
{
return false;
}
// 如果从未备份过,需要创建首次备份
if (settings.Advanced.LastAutoBackupTime == DateTime.MinValue)
{
return true;
}
// 检查是否已超过备份间隔
var daysSinceLastBackup = (DateTime.Now - settings.Advanced.LastAutoBackupTime).TotalDays;
return daysSinceLastBackup >= settings.Advanced.AutoBackupIntervalDays;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"检查自动备份条件时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 执行自动备份
/// </summary>
/// <param name="settings">设置对象</param>
/// <returns>备份是否成功</returns>
public static bool PerformAutoBackup(Settings settings)
{
try
{
// 确保备份目录存在
if (!Directory.Exists(BackupDir))
{
Directory.CreateDirectory(BackupDir);
}
// 检查主配置文件是否存在
if (!File.Exists(SettingsFile))
{
LogHelper.WriteLogToFile("主配置文件不存在,跳过自动备份", LogHelper.LogType.Warning);
return false;
}
// 创建备份文件名(使用当前日期时间)
string backupFileName = $"{BackupPrefix}{DateTime.Now:yyyyMMdd_HHmmss}.json";
string backupPath = Path.Combine(BackupDir, backupFileName);
// 复制主配置文件到备份位置
File.Copy(SettingsFile, backupPath, true);
// 更新最后备份时间
settings.Advanced.LastAutoBackupTime = DateTime.Now;
MainWindow.SaveSettingsToFile();
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"执行自动备份时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 尝试从备份恢复配置文件
/// </summary>
/// <returns>恢复是否成功</returns>
public static bool TryRestoreFromBackup()
{
try
{
// 确保备份目录存在
if (!Directory.Exists(BackupDir))
{
LogHelper.WriteLogToFile("备份目录不存在,无法从备份恢复", LogHelper.LogType.Warning);
return false;
}
// 查找最新的备份文件
var backupFiles = Directory.GetFiles(BackupDir, $"{BackupPrefix}*.json")
.OrderByDescending(f => File.GetCreationTime(f))
.ToArray();
if (backupFiles.Length == 0)
{
LogHelper.WriteLogToFile("没有找到可用的备份文件", LogHelper.LogType.Warning);
return false;
}
// 尝试使用最新的备份文件
string latestBackup = backupFiles[0];
// 验证备份文件是否有效
try
{
string backupJson = File.ReadAllText(latestBackup);
var testSettings = JsonConvert.DeserializeObject<Settings>(backupJson);
if (testSettings == null)
{
LogHelper.WriteLogToFile("备份文件内容无效,无法恢复", LogHelper.LogType.Error);
return false;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"备份文件验证失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
// 备份当前损坏的配置文件(如果存在)
if (File.Exists(SettingsFile))
{
string corruptedBackup = Path.Combine(BackupDir, $"Settings_Corrupted_{DateTime.Now:yyyyMMdd_HHmmss}.json");
File.Copy(SettingsFile, corruptedBackup, true);
}
// 从备份恢复配置文件
File.Copy(latestBackup, SettingsFile, true);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从备份恢复配置文件时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 清理过期的备份文件
/// 保留最近30天的备份文件
/// </summary>
public static void CleanupOldBackups()
{
try
{
if (!Directory.Exists(BackupDir))
{
return;
}
var cutoffDate = DateTime.Now.AddDays(-30);
var backupFiles = Directory.GetFiles(BackupDir, $"{BackupPrefix}*.json");
int deletedCount = 0;
foreach (var file in backupFiles)
{
if (File.GetCreationTime(file) < cutoffDate)
{
File.Delete(file);
deletedCount++;
}
}
if (deletedCount > 0)
{
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理过期备份文件时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 初始化自动备份功能
/// 在应用程序启动时调用
/// </summary>
/// <param name="settings">设置对象</param>
public static void Initialize(Settings settings)
{
try
{
// 检查是否需要执行自动备份
if (ShouldPerformAutoBackup(settings))
{
PerformAutoBackup(settings);
}
// 清理过期备份
CleanupOldBackups();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化自动备份功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
}
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -1,23 +1,23 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Forms;
using System.Windows.Interop;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 防止窗口进入全屏状态的辅助类
/// </summary>
public static partial class AvoidFullScreenHelper
public static class AvoidFullScreenHelper
{
private static readonly DependencyProperty IsAvoidFullScreenEnabledProperty =
DependencyProperty.RegisterAttached(
"IsAvoidFullScreenEnabled",
typeof(bool),
"IsAvoidFullScreenEnabled",
typeof(bool),
typeof(AvoidFullScreenHelper));
private static bool _isBoardMode = false;
private static bool _isBoardMode;
public static void SetBoardMode(bool isBoardMode)
{
_isBoardMode = isBoardMode;
@@ -121,20 +121,20 @@ namespace Ink_Canvas.Helpers
private static Rect GetWorkingArea(Rect windowRect)
{
// 获取所有显示器
var screens = System.Windows.Forms.Screen.AllScreens;
var screens = Screen.AllScreens;
// 确定窗口主要位于哪个显示器上
System.Windows.Forms.Screen targetScreen = null;
Screen targetScreen = null;
double maxIntersection = 0;
foreach (var screen in screens)
{
var screenRect = new Rect(
screen.WorkingArea.X,
screen.WorkingArea.Y,
screen.WorkingArea.Width,
screen.WorkingArea.X,
screen.WorkingArea.Y,
screen.WorkingArea.Width,
screen.WorkingArea.Height);
var intersection = Rect.Intersect(windowRect, screenRect);
if (intersection.Width * intersection.Height > maxIntersection)
{
@@ -142,11 +142,11 @@ namespace Ink_Canvas.Helpers
targetScreen = screen;
}
}
// 如果没找到,使用主显示器
if (targetScreen == null)
targetScreen = System.Windows.Forms.Screen.PrimaryScreen;
targetScreen = Screen.PrimaryScreen;
return new Rect(
targetScreen.WorkingArea.X,
targetScreen.WorkingArea.Y,
@@ -159,21 +159,21 @@ namespace Ink_Canvas.Helpers
// 调整尺寸以适应工作区域
if (windowRect.Width > workingArea.Width)
windowRect.Width = workingArea.Width;
if (windowRect.Height > workingArea.Height)
windowRect.Height = workingArea.Height;
// 调整位置以确保窗口完全在工作区域内
if (windowRect.Left < workingArea.Left)
windowRect.X = workingArea.Left;
else if (windowRect.Right > workingArea.Right)
windowRect.X = workingArea.Right - windowRect.Width;
if (windowRect.Top < workingArea.Top)
windowRect.Y = workingArea.Top;
else if (windowRect.Bottom > workingArea.Bottom)
windowRect.Y = workingArea.Bottom - windowRect.Height;
return windowRect;
}
}
+389
View File
@@ -0,0 +1,389 @@
using AForge.Video;
using AForge.Video.DirectShow;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
public class CameraService : IDisposable
{
private VideoCaptureDevice _videoSource;
private bool _isCapturing;
private Bitmap _currentFrame;
private readonly object _frameLock = new object();
private Dispatcher _dispatcher;
// 新增属性
private int _rotationAngle = 0; // 0=0度,1=90度,2=180度,3=270度
private int _resolutionWidth = 640;
private int _resolutionHeight = 480;
public event EventHandler<Bitmap> FrameReceived;
public event EventHandler<string> ErrorOccurred;
public bool IsCapturing => _isCapturing;
public List<FilterInfo> AvailableCameras { get; private set; }
public FilterInfo CurrentCamera { get; private set; }
// 新增属性
public int RotationAngle
{
get => _rotationAngle;
set => _rotationAngle = Math.Max(0, Math.Min(3, value));
}
public int ResolutionWidth
{
get => _resolutionWidth;
set => _resolutionWidth = Math.Max(320, Math.Min(1920, value));
}
public int ResolutionHeight
{
get => _resolutionHeight;
set => _resolutionHeight = Math.Max(240, Math.Min(1080, value));
}
public CameraService()
{
_dispatcher = Dispatcher.CurrentDispatcher;
AvailableCameras = new List<FilterInfo>();
RefreshCameraList();
}
public CameraService(int rotationAngle, int resolutionWidth, int resolutionHeight)
{
_dispatcher = Dispatcher.CurrentDispatcher;
AvailableCameras = new List<FilterInfo>();
_rotationAngle = rotationAngle;
_resolutionWidth = resolutionWidth;
_resolutionHeight = resolutionHeight;
RefreshCameraList();
}
/// <summary>
/// 刷新可用摄像头列表
/// </summary>
public void RefreshCameraList()
{
try
{
AvailableCameras.Clear();
var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in videoDevices)
{
AvailableCameras.Add(device);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新摄像头列表失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"刷新摄像头列表失败: {ex.Message}");
}
}
/// <summary>
/// 开始摄像头预览
/// </summary>
/// <param name="cameraIndex">摄像头索引</param>
public bool StartPreview(int cameraIndex = 0)
{
try
{
if (AvailableCameras.Count == 0)
{
RefreshCameraList();
if (AvailableCameras.Count == 0)
{
ErrorOccurred?.Invoke(this, "未找到可用的摄像头设备");
return false;
}
}
if (cameraIndex < 0 || cameraIndex >= AvailableCameras.Count)
{
ErrorOccurred?.Invoke(this, "摄像头索引超出范围");
return false;
}
// 停止当前预览
StopPreview();
CurrentCamera = AvailableCameras[cameraIndex];
_videoSource = new VideoCaptureDevice(CurrentCamera.MonikerString);
// 设置视频源事件处理
_videoSource.NewFrame += VideoSource_NewFrame;
// 启动视频源
_videoSource.Start();
_isCapturing = true;
LogHelper.WriteLogToFile($"开始摄像头预览: {CurrentCamera.Name}");
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动摄像头预览失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"启动摄像头预览失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 停止摄像头预览
/// </summary>
public void StopPreview()
{
try
{
if (_videoSource != null && _videoSource.IsRunning)
{
_videoSource.SignalToStop();
_videoSource.WaitForStop();
_videoSource.NewFrame -= VideoSource_NewFrame;
_videoSource = null;
}
_isCapturing = false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"停止摄像头预览失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 切换到指定摄像头
/// </summary>
/// <param name="cameraIndex">摄像头索引</param>
public bool SwitchCamera(int cameraIndex)
{
try
{
if (cameraIndex < 0 || cameraIndex >= AvailableCameras.Count)
{
ErrorOccurred?.Invoke(this, "摄像头索引超出范围");
return false;
}
return StartPreview(cameraIndex);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换摄像头失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"切换摄像头失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 获取当前帧的BitmapSource(WPF格式),直接返回可用的WPF位图
/// </summary>
public BitmapSource GetCurrentFrameAsBitmapSource()
{
lock (_frameLock)
{
if (_currentFrame == null)
return null;
try
{
// 验证位图有效性
if (_currentFrame.Width <= 0 || _currentFrame.Height <= 0)
return null;
// 使用更安全的方法转换位图
var bitmapData = _currentFrame.LockBits(
new Rectangle(0, 0, _currentFrame.Width, _currentFrame.Height),
ImageLockMode.ReadOnly,
_currentFrame.PixelFormat);
try
{
// 根据像素格式选择合适的WPF像素格式
System.Windows.Media.PixelFormat wpfPixelFormat;
switch (_currentFrame.PixelFormat)
{
case PixelFormat.Format24bppRgb:
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
break;
case PixelFormat.Format32bppArgb:
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgra32;
break;
case PixelFormat.Format32bppRgb:
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr32;
break;
default:
wpfPixelFormat = System.Windows.Media.PixelFormats.Bgr24;
break;
}
var bitmapSource = BitmapSource.Create(
bitmapData.Width,
bitmapData.Height,
_currentFrame.HorizontalResolution,
_currentFrame.VerticalResolution,
wpfPixelFormat,
null,
bitmapData.Scan0,
bitmapData.Stride * bitmapData.Height,
bitmapData.Stride);
bitmapSource.Freeze();
return bitmapSource;
}
finally
{
_currentFrame.UnlockBits(bitmapData);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"转换帧为BitmapSource失败: {ex.Message}", LogHelper.LogType.Error);
return null;
}
}
}
/// <summary>
/// 视频源新帧事件处理
/// </summary>
private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
lock (_frameLock)
{
// 释放之前的帧
_currentFrame?.Dispose();
// 创建新的位图,避免Clone的问题
var sourceFrame = eventArgs.Frame;
if (sourceFrame != null)
{
try
{
var width = sourceFrame.Width;
var height = sourceFrame.Height;
if (width > 0 && height > 0)
{
// 应用旋转
Bitmap rotatedFrame = ApplyRotation(sourceFrame);
// 应用分辨率调整
_currentFrame = ResizeImage(rotatedFrame, _resolutionWidth, _resolutionHeight);
rotatedFrame?.Dispose();
}
else
{
_currentFrame = null;
}
}
catch (Exception frameEx)
{
LogHelper.WriteLogToFile($"处理源帧失败: {frameEx.Message}", LogHelper.LogType.Error);
_currentFrame = null;
}
}
else
{
_currentFrame = null;
}
}
// 在UI线程中触发事件
_dispatcher.BeginInvoke(new Action(() =>
{
FrameReceived?.Invoke(this, _currentFrame);
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理新帧失败: {ex.Message}", LogHelper.LogType.Error);
ErrorOccurred?.Invoke(this, $"处理新帧失败: {ex.Message}");
}
}
/// <summary>
/// 获取摄像头名称列表
/// </summary>
public List<string> GetCameraNames()
{
return AvailableCameras.Select(camera => camera.Name).ToList();
}
/// <summary>
/// 检查是否有可用摄像头
/// </summary>
public bool HasAvailableCameras()
{
if (AvailableCameras.Count == 0)
{
RefreshCameraList();
}
return AvailableCameras.Count > 0;
}
/// <summary>
/// 应用旋转到图像
/// </summary>
private Bitmap ApplyRotation(Bitmap source)
{
if (_rotationAngle == 0)
return new Bitmap(source);
var rotationType = RotateFlipType.RotateNoneFlipNone;
switch (_rotationAngle)
{
case 1: rotationType = RotateFlipType.Rotate90FlipNone; break;
case 2: rotationType = RotateFlipType.Rotate180FlipNone; break;
case 3: rotationType = RotateFlipType.Rotate270FlipNone; break;
}
var rotated = new Bitmap(source);
rotated.RotateFlip(rotationType);
return rotated;
}
/// <summary>
/// 调整图像大小
/// </summary>
private Bitmap ResizeImage(Bitmap source, int width, int height)
{
if (source.Width == width && source.Height == height)
return new Bitmap(source);
var resized = new Bitmap(width, height, PixelFormat.Format24bppRgb);
using (var graphics = Graphics.FromImage(resized))
{
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
graphics.DrawImage(source, 0, 0, width, height);
}
return resized;
}
public void Dispose()
{
StopPreview();
lock (_frameLock)
{
_currentFrame?.Dispose();
}
}
}
}
+29 -47
View File
@@ -9,125 +9,107 @@ namespace Ink_Canvas.Converter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value == true)
if ((bool)value)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value == true)
if ((bool)value)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
return Visibility.Collapsed;
}
}
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Visibility visibility = (Visibility)value;
if (visibility == Visibility.Visible)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Visibility visibility = (Visibility)value;
if (visibility == Visibility.Visible)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
return Visibility.Visible;
}
}
public class IntNumberToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((double)value == 0)
{
return "无限制";
}
else
{
return ((double)value).ToString() + "人";
}
return ((double)value) + "人";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((double)value == 0)
{
return "无限制";
}
else
{
return ((double)value).ToString() + "人";
}
return ((double)value) + "人";
}
}
public class IntNumberToString2 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((double)value == 0)
{
return "自动截图";
}
else
{
return ((double)value).ToString() + "条";
}
return ((double)value) + "条";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((double)value == 0)
{
return "自动截图";
}
else
{
return ((double)value).ToString() + "条";
}
return ((double)value) + "条";
}
}
public class IsEnabledToOpacityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isChecked = (bool)value;
if (isChecked == true)
if (isChecked)
{
return 1d;
}
else
{
return 0.35;
}
return 0.35;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }
}
}
+34 -18
View File
@@ -1,48 +1,64 @@
using System;
using System.IO;
using System.Windows;
namespace Ink_Canvas.Helpers {
internal class DelAutoSavedFiles {
public static void DeleteFilesOlder(string directoryPath, int daysThreshold) {
namespace Ink_Canvas.Helpers
{
internal class DelAutoSavedFiles
{
public static void DeleteFilesOlder(string directoryPath, int daysThreshold)
{
string[] extensionsToDel = { ".icstk", ".png" };
if (Directory.Exists(directoryPath)) {
if (Directory.Exists(directoryPath))
{
// 获取目录中的所有子目录
string[] subDirectories = Directory.GetDirectories(directoryPath, "*", SearchOption.AllDirectories);
foreach (string subDirectory in subDirectories) {
try {
foreach (string subDirectory in subDirectories)
{
try
{
// 获取子目录下的所有文件
string[] files = Directory.GetFiles(subDirectory);
foreach (string filePath in files) {
foreach (string filePath in files)
{
// 获取文件的创建日期
DateTime creationDate = File.GetCreationTime(filePath);
// 获取文件的扩展名
string fileExtension = Path.GetExtension(filePath);
// 如果文件的创建日期早于指定天数且是要删除的扩展名,则删除文件
if (creationDate < DateTime.Now.AddDays(-daysThreshold)) {
if (creationDate < DateTime.Now.AddDays(-daysThreshold))
{
if (Array.Exists(extensionsToDel, ext => ext.Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
|| Path.GetFileName(filePath).Equals("Position", StringComparison.OrdinalIgnoreCase)) {
|| Path.GetFileName(filePath).Equals("Position", StringComparison.OrdinalIgnoreCase))
{
File.Delete(filePath);
}
}
}
} catch (Exception ex) {
LogHelper.WriteLogToFile("DelAutoSavedFiles | 处理文件时出错: " + ex.ToString(), LogHelper.LogType.Error);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile("DelAutoSavedFiles | 处理文件时出错: " + ex, LogHelper.LogType.Error);
}
}
try { // 递归删除空文件夹
try
{ // 递归删除空文件夹
DeleteEmptyFolders(directoryPath);
} catch (Exception ex) {
LogHelper.WriteLogToFile("DelAutoSavedFiles | 处理文件时出错: " + ex.ToString(), LogHelper.LogType.Error);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile("DelAutoSavedFiles | 处理文件时出错: " + ex, LogHelper.LogType.Error);
}
}
}
private static void DeleteEmptyFolders(string directoryPath) {
foreach (string dir in Directory.GetDirectories(directoryPath)) {
private static void DeleteEmptyFolders(string directoryPath)
{
foreach (string dir in Directory.GetDirectories(directoryPath))
{
DeleteEmptyFolders(dir);
if (Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0) {
if (Directory.GetFiles(dir).Length == 0 && Directory.GetDirectories(dir).Length == 0)
{
Directory.Delete(dir, false);
}
}
+6 -7
View File
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace Ink_Canvas.Helpers
@@ -18,10 +14,13 @@ namespace Ink_Canvas.Helpers
/// <param name="inv">同步的對象,一般傳入控件,不需要可null</param>
public void DebounceAction(int timeMs, ISynchronizeInvoke inv, Action action)
{
lock (this) {
if (_timerDebounce == null) {
lock (this)
{
if (_timerDebounce == null)
{
_timerDebounce = new Timer(timeMs) { AutoReset = false };
_timerDebounce.Elapsed += (o, e) => {
_timerDebounce.Elapsed += (o, e) =>
{
_timerDebounce.Stop(); _timerDebounce.Close(); _timerDebounce = null;
InvokeAction(action, inv);
};
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
namespace Ink_Canvas.Helpers
{
@@ -70,7 +71,7 @@ namespace Ink_Canvas.Helpers
[FieldOffset(8)]
private DateTime date;
[FieldOffset(8)]
private System.Runtime.InteropServices.ComTypes.FILETIME filetime;
private FILETIME filetime;
[FieldOffset(8)]
private Blob blobVal;
@@ -115,7 +116,7 @@ namespace Ink_Canvas.Helpers
case VarEnum.VT_BLOB:
return GetBlob();
}
throw new NotImplementedException("PropVariant " + ve.ToString());
throw new NotImplementedException("PropVariant " + ve);
}
}
}
@@ -144,17 +145,17 @@ namespace Ink_Canvas.Helpers
#region "Interfaces"
[ComImport(), Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStore
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetCount([Out(), In()] ref uint cProps);
void GetCount([Out, In] ref uint cProps);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAt([In()] uint iProp, ref PropertyKey pkey);
void GetAt([In] uint iProp, ref PropertyKey pkey);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetValue([In()] ref PropertyKey key, ref PropVariant pv);
void GetValue([In] ref PropertyKey key, ref PropVariant pv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetValue([In()] ref PropertyKey key, [In()] ref PropVariant pv);
void SetValue([In] ref PropertyKey key, [In] ref PropVariant pv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void Commit();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
@@ -0,0 +1,589 @@
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Windows;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 文件关联管理器,用于注册和处理.icstk文件的关联
/// </summary>
public static class FileAssociationManager
{
private const string FileExtension = ".icstk";
private const string FileTypeName = "InkCanvasStrokesFile";
private const string AppName = "Ink Canvas";
private const string AppDescription = "Ink Canvas Strokes File";
// IPC相关常量
private const string IpcMutexName = "InkCanvasFileAssociationIpc";
private const string IpcEventName = "InkCanvasFileAssociationEvent";
private const string IpcFilePrefix = "InkCanvasFileAssociation_";
private const string IpcBoardModePrefix = "InkCanvasBoardMode_";
private const string IpcShowModePrefix = "InkCanvasShowMode_";
private const int IpcTimeout = 5000; // 5秒超时
/// <summary>
/// 注册.icstk文件关联
/// </summary>
public static bool RegisterFileAssociation()
{
try
{
string exePath = Process.GetCurrentProcess().MainModule.FileName;
// 注册文件类型
using (RegistryKey fileTypeKey = Registry.ClassesRoot.CreateSubKey(FileTypeName))
{
fileTypeKey.SetValue("", AppDescription);
fileTypeKey.SetValue("FriendlyTypeName", AppDescription);
// 设置默认图标
using (RegistryKey defaultIconKey = fileTypeKey.CreateSubKey("DefaultIcon"))
{
defaultIconKey.SetValue("", $"\"{exePath}\",0");
}
// 设置打开命令
using (RegistryKey shellKey = fileTypeKey.CreateSubKey("shell"))
using (RegistryKey openKey = shellKey.CreateSubKey("open"))
using (RegistryKey commandKey = openKey.CreateSubKey("command"))
{
commandKey.SetValue("", $"\"{exePath}\" \"%1\"");
}
}
// 注册文件扩展名
using (RegistryKey extensionKey = Registry.ClassesRoot.CreateSubKey(FileExtension))
{
extensionKey.SetValue("", FileTypeName);
}
// 刷新系统文件关联缓存
RefreshSystemFileAssociations();
LogHelper.WriteLogToFile($"成功注册{FileExtension}文件关联", LogHelper.LogType.Event);
return true;
}
catch (SecurityException ex)
{
LogHelper.WriteLogToFile($"注册文件关联时权限不足: {ex.Message}", LogHelper.LogType.Error);
return false;
}
catch (UnauthorizedAccessException ex)
{
LogHelper.WriteLogToFile($"注册文件关联时访问被拒绝: {ex.Message}", LogHelper.LogType.Error);
return false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注册文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 注销.icstk文件关联
/// </summary>
public static bool UnregisterFileAssociation()
{
try
{
// 删除文件扩展名关联
Registry.ClassesRoot.DeleteSubKeyTree(FileExtension, false);
// 删除文件类型定义
Registry.ClassesRoot.DeleteSubKeyTree(FileTypeName, false);
// 刷新系统文件关联缓存
RefreshSystemFileAssociations();
LogHelper.WriteLogToFile($"成功注销{FileExtension}文件关联", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注销文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 检查文件关联是否已注册
/// </summary>
public static bool IsFileAssociationRegistered()
{
try
{
using (RegistryKey extensionKey = Registry.ClassesRoot.OpenSubKey(FileExtension))
{
if (extensionKey == null) return false;
string fileType = extensionKey.GetValue("") as string;
if (string.IsNullOrEmpty(fileType)) return false;
using (RegistryKey fileTypeKey = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (fileTypeKey == null) return false;
using (RegistryKey shellKey = fileTypeKey.OpenSubKey("shell\\open\\command"))
{
if (shellKey == null) return false;
string command = shellKey.GetValue("") as string;
if (string.IsNullOrEmpty(command)) return false;
// 检查命令是否指向当前应用程序
string currentExePath = Process.GetCurrentProcess().MainModule.FileName;
return command.Contains(currentExePath);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"检查文件关联状态时出错: {ex.Message}", LogHelper.LogType.Error);
}
return false;
}
/// <summary>
/// 显示文件关联状态
/// </summary>
public static void ShowFileAssociationStatus()
{
bool isRegistered = IsFileAssociationRegistered();
LogHelper.WriteLogToFile($"{FileExtension}文件关联状态: {(isRegistered ? "" : "")}", LogHelper.LogType.Event);
}
/// <summary>
/// 刷新系统文件关联缓存
/// </summary>
private static void RefreshSystemFileAssociations()
{
try
{
// 通知系统文件关联已更改
SHChangeNotify(0x08000000, 0, IntPtr.Zero, IntPtr.Zero);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新文件关联缓存时出错: {ex.Message}", LogHelper.LogType.Warning);
}
}
/// <summary>
/// 处理命令行参数中的文件路径
/// </summary>
/// <param name="args">命令行参数</param>
/// <returns>找到的.icstk文件路径,如果没有找到则返回null</returns>
public static string GetIcstkFileFromArgs(string[] args)
{
if (args == null || args.Length == 0) return null;
foreach (string arg in args)
{
if (string.IsNullOrEmpty(arg)) continue;
// 检查是否为.icstk文件
if (Path.GetExtension(arg).Equals(FileExtension, StringComparison.OrdinalIgnoreCase))
{
// 检查文件是否存在
if (File.Exists(arg))
{
LogHelper.WriteLogToFile($"从命令行参数中找到.icstk文件: {arg}", LogHelper.LogType.Event);
return arg;
}
else
{
LogHelper.WriteLogToFile($"命令行参数中的.icstk文件不存在: {arg}", LogHelper.LogType.Warning);
}
}
}
return null;
}
/// <summary>
/// 尝试通过IPC将文件路径发送给已运行的实例
/// </summary>
/// <param name="filePath">要打开的文件路径</param>
/// <returns>是否成功发送</returns>
public static bool TrySendFileToExistingInstance(string filePath)
{
try
{
LogHelper.WriteLogToFile($"尝试通过IPC发送文件路径给已运行实例: {filePath}", LogHelper.LogType.Event);
// 创建IPC文件
string tempDir = Path.GetTempPath();
string ipcFileName = IpcFilePrefix + Guid.NewGuid().ToString("N") + ".tmp";
string ipcFilePath = Path.Combine(tempDir, ipcFileName);
// 写入文件路径到IPC文件
File.WriteAllText(ipcFilePath, filePath, Encoding.UTF8);
// 创建事件通知已运行实例
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
ipcEvent.Set();
}
// 等待一段时间让已运行实例处理文件
Thread.Sleep(1000);
// 清理IPC文件
try
{
if (File.Exists(ipcFilePath))
{
File.Delete(ipcFilePath);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
}
LogHelper.WriteLogToFile("IPC文件路径发送完成", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"通过IPC发送文件路径失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 尝试通过IPC将白板模式命令发送给已运行的实例
/// </summary>
/// <returns>是否成功发送</returns>
public static bool TrySendBoardModeCommandToExistingInstance()
{
try
{
LogHelper.WriteLogToFile("尝试通过IPC发送白板模式命令给已运行实例", LogHelper.LogType.Event);
// 创建IPC文件
string tempDir = Path.GetTempPath();
string ipcFileName = IpcBoardModePrefix + Guid.NewGuid().ToString("N") + ".tmp";
string ipcFilePath = Path.Combine(tempDir, ipcFileName);
// 写入白板模式命令到IPC文件
File.WriteAllText(ipcFilePath, "BOARD_MODE", Encoding.UTF8);
// 创建事件通知已运行实例
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
ipcEvent.Set();
}
// 等待一段时间让已运行实例处理命令
Thread.Sleep(1000);
// 清理IPC文件
try
{
if (File.Exists(ipcFilePath))
{
File.Delete(ipcFilePath);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
}
LogHelper.WriteLogToFile("IPC白板模式命令发送完成", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"通过IPC发送白板模式命令失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 尝试通过IPC将展开浮动栏命令发送给已运行的实例
/// </summary>
/// <returns>是否成功发送</returns>
public static bool TrySendShowModeCommandToExistingInstance()
{
try
{
LogHelper.WriteLogToFile("尝试通过IPC发送展开浮动栏命令给已运行实例", LogHelper.LogType.Event);
// 创建IPC文件
string tempDir = Path.GetTempPath();
string ipcFileName = IpcShowModePrefix + Guid.NewGuid().ToString("N") + ".tmp";
string ipcFilePath = Path.Combine(tempDir, ipcFileName);
// 写入展开浮动栏命令到IPC文件
File.WriteAllText(ipcFilePath, "SHOW_MODE", Encoding.UTF8);
// 创建事件通知已运行实例
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
ipcEvent.Set();
}
// 等待一段时间让已运行实例处理命令
Thread.Sleep(1000);
// 清理IPC文件
try
{
if (File.Exists(ipcFilePath))
{
File.Delete(ipcFilePath);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
}
LogHelper.WriteLogToFile("IPC展开浮动栏命令发送完成", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"通过IPC发送展开浮动栏命令失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 启动IPC监听器,等待其他实例发送文件路径
/// </summary>
public static void StartIpcListener()
{
try
{
Thread ipcThread = new Thread(() =>
{
try
{
LogHelper.WriteLogToFile("启动IPC监听器", LogHelper.LogType.Event);
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
while (true)
{
// 等待IPC事件
if (ipcEvent.WaitOne(IpcTimeout))
{
// 处理IPC文件
ProcessIpcFiles();
// 重置事件
ipcEvent.Reset();
}
// 检查应用是否还在运行
if (Application.Current == null || Application.Current.Dispatcher == null)
{
break;
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC监听器出错: {ex.Message}", LogHelper.LogType.Error);
}
});
ipcThread.IsBackground = true;
ipcThread.Start();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动IPC监听器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 处理IPC文件
/// </summary>
private static void ProcessIpcFiles()
{
try
{
string tempDir = Path.GetTempPath();
// 处理文件路径IPC文件
string[] ipcFiles = Directory.GetFiles(tempDir, IpcFilePrefix + "*.tmp");
foreach (string ipcFile in ipcFiles)
{
try
{
// 读取文件路径
string filePath = File.ReadAllText(ipcFile, Encoding.UTF8);
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
LogHelper.WriteLogToFile($"IPC接收到文件路径: {filePath}", LogHelper.LogType.Event);
// 在UI线程中处理文件打开
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 获取主窗口并打开文件
if (Application.Current.MainWindow is MainWindow mainWindow)
{
mainWindow.OpenSingleStrokeFile(filePath);
mainWindow.ShowNotification($"已加载墨迹文件: {Path.GetFileName(filePath)}");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC处理文件打开失败: {ex.Message}", LogHelper.LogType.Error);
}
}));
}
// 删除IPC文件
File.Delete(ipcFile);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
// 尝试删除损坏的IPC文件
try
{
if (File.Exists(ipcFile))
{
File.Delete(ipcFile);
}
}
catch { }
}
}
// 处理白板模式命令IPC文件
string[] boardModeFiles = Directory.GetFiles(tempDir, IpcBoardModePrefix + "*.tmp");
foreach (string ipcFile in boardModeFiles)
{
try
{
// 读取命令内容
string command = File.ReadAllText(ipcFile, Encoding.UTF8);
if (command == "BOARD_MODE")
{
LogHelper.WriteLogToFile("IPC接收到白板模式命令", LogHelper.LogType.Event);
// 在UI线程中处理白板模式切换
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 获取主窗口并切换到白板模式
if (Application.Current.MainWindow is MainWindow mainWindow)
{
mainWindow.SwitchToBoardMode();
mainWindow.ShowNotification("已切换到白板模式");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC处理白板模式切换失败: {ex.Message}", LogHelper.LogType.Error);
}
}));
}
// 删除IPC文件
File.Delete(ipcFile);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理白板模式IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
// 尝试删除损坏的IPC文件
try
{
if (File.Exists(ipcFile))
{
File.Delete(ipcFile);
}
}
catch { }
}
}
// 处理展开浮动栏命令IPC文件
string[] showModeFiles = Directory.GetFiles(tempDir, IpcShowModePrefix + "*.tmp");
foreach (string ipcFile in showModeFiles)
{
try
{
// 读取命令内容
string command = File.ReadAllText(ipcFile, Encoding.UTF8);
if (command == "SHOW_MODE")
{
LogHelper.WriteLogToFile("IPC接收到展开浮动栏命令", LogHelper.LogType.Event);
// 在UI线程中处理展开浮动栏
Application.Current.Dispatcher.BeginInvoke(new Action(async () =>
{
try
{
// 获取主窗口并展开浮动栏
if (Application.Current.MainWindow is MainWindow mainWindow)
{
// 如果当前处于收纳模式,则展开浮动栏
if (mainWindow.isFloatingBarFolded)
{
await mainWindow.UnFoldFloatingBar(new object());
}
mainWindow.ShowNotification("已退出收纳模式并恢复浮动栏");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC处理展开浮动栏失败: {ex.Message}", LogHelper.LogType.Error);
}
}));
}
// 删除IPC文件
File.Delete(ipcFile);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理展开浮动栏IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
// 尝试删除损坏的IPC文件
try
{
if (File.Exists(ipcFile))
{
File.Delete(ipcFile);
}
}
catch { }
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理IPC文件时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
[DllImport("shell32.dll")]
private static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
}
}
File diff suppressed because it is too large Load Diff
+28 -8
View File
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace Ink_Canvas.Helpers
{
@@ -24,7 +25,8 @@ namespace Ink_Canvas.Helpers
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public struct RECT
{
public int Left;
public int Top;
public int Right;
@@ -34,7 +36,8 @@ namespace Ink_Canvas.Helpers
public int Height => Bottom - Top;
}
public static string WindowTitle() {
public static string WindowTitle()
{
IntPtr foregroundWindowHandle = GetForegroundWindow();
const int nChars = 256;
@@ -44,7 +47,8 @@ namespace Ink_Canvas.Helpers
return windowTitle.ToString();
}
public static string WindowClassName() {
public static string WindowClassName()
{
IntPtr foregroundWindowHandle = GetForegroundWindow();
const int nChars = 256;
@@ -54,7 +58,8 @@ namespace Ink_Canvas.Helpers
return className.ToString();
}
public static RECT WindowRect() {
public static RECT WindowRect()
{
IntPtr foregroundWindowHandle = GetForegroundWindow();
RECT windowRect;
@@ -63,15 +68,19 @@ namespace Ink_Canvas.Helpers
return windowRect;
}
public static string ProcessName() {
public static string ProcessName()
{
IntPtr foregroundWindowHandle = GetForegroundWindow();
uint processId;
GetWindowThreadProcessId(foregroundWindowHandle, out processId);
try {
try
{
Process process = Process.GetProcessById((int)processId);
return process.ProcessName;
} catch (ArgumentException) {
}
catch (ArgumentException)
{
// Process with the given ID not found
return "Unknown";
}
@@ -88,10 +97,21 @@ namespace Ink_Canvas.Helpers
Process process = Process.GetProcessById((int)processId);
return process.MainModule.FileName;
}
catch {
catch
{
// Process with the given ID not found
return "Unknown";
}
}
public static double GetTaskbarHeight(Screen screen, double dpiScaleY)
{
// 获取工作区和屏幕高度的差值
var workingArea = screen.WorkingArea;
var bounds = screen.Bounds;
int taskbarHeight = bounds.Height - workingArea.Height;
// 考虑 DPI 缩放
return taskbarHeight / dpiScaleY;
}
}
}
+10 -12
View File
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
// 由衷感謝 lindexi 提供的 《WPF 稳定的全屏化窗口方法》
// 文章鏈接:https://blog.lindexi.com/post/WPF-%E7%A8%B3%E5%AE%9A%E7%9A%84%E5%85%A8%E5%B1%8F%E5%8C%96%E7%AA%97%E5%8F%A3%E6%96%B9%E6%B3%95.html
@@ -83,7 +81,7 @@ namespace Ink_Canvas.Helpers
public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
public static IntPtr GetWindowLongPtr(IntPtr hWnd, GetWindowLongFields nIndex) =>
GetWindowLongPtr(hWnd, (int) nIndex);
GetWindowLongPtr(hWnd, (int)nIndex);
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
{
@@ -101,7 +99,7 @@ namespace Ink_Canvas.Helpers
public static extern IntPtr GetWindowLongPtr_x64(IntPtr hWnd, int nIndex);
public static IntPtr SetWindowLongPtr(IntPtr hWnd, GetWindowLongFields nIndex, IntPtr dwNewLong) =>
SetWindowLongPtr(hWnd, (int) nIndex, dwNewLong);
SetWindowLongPtr(hWnd, (int)nIndex, dwNewLong);
public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
@@ -266,8 +264,8 @@ namespace Ink_Canvas.Helpers
/// </summary>
public int Width
{
get { return unchecked((int) (Right - Left)); }
set { Right = unchecked((int) (Left + value)); }
get { return unchecked(Right - Left); }
set { Right = unchecked(Left + value); }
}
/// <summary>
@@ -275,8 +273,8 @@ namespace Ink_Canvas.Helpers
/// </summary>
public int Height
{
get { return unchecked((int) (Bottom - Top)); }
set { Bottom = unchecked((int) (Top + value)); }
get { return unchecked(Bottom - Top); }
set { Bottom = unchecked(Top + value); }
}
public bool Equals(Rectangle other)
@@ -298,10 +296,10 @@ namespace Ink_Canvas.Helpers
{
unchecked
{
var hashCode = (int) Left;
hashCode = (hashCode * 397) ^ (int) Top;
hashCode = (hashCode * 397) ^ (int) Right;
hashCode = (hashCode * 397) ^ (int) Bottom;
var hashCode = Left;
hashCode = (hashCode * 397) ^ Top;
hashCode = (hashCode * 397) ^ Right;
hashCode = (hashCode * 397) ^ Bottom;
return hashCode;
}
}
+9 -12
View File
@@ -67,12 +67,12 @@ namespace Ink_Canvas.Helpers
//获取当前窗口的位置大小状态并保存
var placement = new WINDOWPLACEMENT();
placement.Size = (uint) Marshal.SizeOf(placement);
placement.Size = (uint)Marshal.SizeOf(placement);
Win32.User32.GetWindowPlacement(hwnd, ref placement);
window.SetValue(BeforeFullScreenWindowPlacementProperty, placement);
//修改窗口样式
var style = (WindowStyles) Win32.User32.GetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE);
var style = (WindowStyles)Win32.User32.GetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE);
window.SetValue(BeforeFullScreenWindowStyleProperty, style);
//将窗口恢复到还原模式,在有标题栏的情况下最大化模式下无法全屏,
//这里采用还原,不修改标题栏的方式
@@ -81,7 +81,7 @@ namespace Ink_Canvas.Helpers
//去掉WS_MAXIMIZEBOX,禁用最大化,如果最大化会退出全屏
//去掉WS_MAXIMIZE,使窗口变成还原状态,不使用ShowWindow(hwnd, ShowWindowCommands.SW_RESTORE),避免看到窗口变成还原状态这一过程(也避免影响窗口的Visible状态)
style &= (~(WindowStyles.WS_THICKFRAME | WindowStyles.WS_MAXIMIZEBOX | WindowStyles.WS_MAXIMIZE));
Win32.User32.SetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE, (IntPtr) style);
Win32.User32.SetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE, (IntPtr)style);
//禁用 DWM 过渡动画 忽略返回值,若DWM关闭不做处理
Win32.Dwmapi.DwmSetWindowAttribute(hwnd, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 1,
@@ -95,8 +95,8 @@ namespace Ink_Canvas.Helpers
//不能用 placement 的坐标,placement是工作区坐标,不是屏幕坐标。
//使用窗口当前的矩形调用下设置窗口位置和尺寸的方法,让Hook来进行调整窗口位置和尺寸到全屏模式
Win32.User32.SetWindowPos(hwnd, (IntPtr) HwndZOrder.HWND_TOPMOST, rect.Left, rect.Top, rect.Width,
rect.Height, (int) WindowPositionFlags.SWP_NOZORDER);
Win32.User32.SetWindowPos(hwnd, (IntPtr)HwndZOrder.HWND_TOPMOST, rect.Left, rect.Top, rect.Width,
rect.Height, (int)WindowPositionFlags.SWP_NOZORDER);
}
}
}
@@ -139,7 +139,7 @@ namespace Ink_Canvas.Helpers
//不要改变Style里的WS_MAXIMIZE,否则会使窗口变成最大化状态,但是尺寸不对
//也不要设置回Style里的WS_MINIMIZE,否则会导致窗口最小化按钮显示成还原按钮
Win32.User32.SetWindowLongPtr(hwnd, GetWindowLongFields.GWL_STYLE,
(IntPtr) (style & (~(WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE))));
(IntPtr)(style & (~(WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE))));
if ((style & WindowStyles.WS_MINIMIZE) != 0)
{
@@ -201,7 +201,7 @@ namespace Ink_Canvas.Helpers
try
{
//得到WINDOWPOS结构体
var pos = (WindowPosition) Marshal.PtrToStructure(lParam, typeof(WindowPosition));
var pos = (WindowPosition)Marshal.PtrToStructure(lParam, typeof(WindowPosition));
if ((pos.Flags & WindowPositionFlags.SWP_NOMOVE) != 0 &&
(pos.Flags & WindowPositionFlags.SWP_NOSIZE) != 0)
@@ -245,7 +245,7 @@ namespace Ink_Canvas.Helpers
//使用目标矩形获取显示器信息
var monitor = Win32.User32.MonitorFromRect(targetRect, MonitorFlag.MONITOR_DEFAULTTOPRIMARY);
var info = new MonitorInfo();
info.Size = (uint) Marshal.SizeOf(info);
info.Size = (uint)Marshal.SizeOf(info);
if (Win32.User32.GetMonitorInfo(monitor, ref info))
{
//基于显示器信息设置窗口尺寸位置
@@ -278,10 +278,7 @@ namespace Ink_Canvas.Helpers
window.Width = logicalSize.X;
window.Height = logicalSize.Y;
}
else
{
//这个hwnd是前面从Window来的,如果现在他不是Window...... 你信么
}
//这个hwnd是前面从Window来的,如果现在他不是Window...... 你信么
}
//将修改后的结构体拷贝回去
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 硬件加速的墨迹处理器,利用WPF的GPU渲染能力
/// </summary>
public class HardwareAcceleratedInkProcessor
{
private readonly RenderTargetBitmap _renderTarget;
private readonly DrawingVisual _drawingVisual;
private bool _isInitialized;
public HardwareAcceleratedInkProcessor(int width = 1920, int height = 1080)
{
// 创建硬件加速的渲染目标
_renderTarget = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
_drawingVisual = new DrawingVisual();
// 启用硬件加速
RenderOptions.SetBitmapScalingMode(_drawingVisual, BitmapScalingMode.HighQuality);
RenderOptions.SetEdgeMode(_drawingVisual, EdgeMode.Aliased);
_isInitialized = true;
}
/// <summary>
/// 使用GPU加速的贝塞尔曲线平滑
/// </summary>
public async Task<Stroke> SmoothStrokeWithGPU(Stroke originalStroke)
{
if (!_isInitialized || originalStroke == null || originalStroke.StylusPoints.Count < 2)
return originalStroke;
return await Task.Run(() =>
{
try
{
// 使用PathGeometry进行硬件加速的曲线拟合
var pathGeometry = CreateSmoothPathGeometry(originalStroke.StylusPoints);
// 将PathGeometry转换回StylusPoint集合
var smoothedPoints = ConvertPathGeometryToStylusPoints(pathGeometry, originalStroke.StylusPoints);
return new Stroke(new StylusPointCollection(smoothedPoints))
{
DrawingAttributes = originalStroke.DrawingAttributes.Clone()
};
}
catch
{
return originalStroke;
}
});
}
/// <summary>
/// 创建平滑的路径几何体
/// </summary>
private PathGeometry CreateSmoothPathGeometry(StylusPointCollection points)
{
var pathGeometry = new PathGeometry();
var pathFigure = new PathFigure();
if (points.Count < 2) return pathGeometry;
pathFigure.StartPoint = new Point(points[0].X, points[0].Y);
// 使用贝塞尔曲线段创建平滑路径,增加插点密度
for (int i = 0; i < points.Count - 1; i += 2) // 从i+=3改为i+=2,增加插点密度
{
var p1 = i + 1 < points.Count ? new Point(points[i + 1].X, points[i + 1].Y) : pathFigure.StartPoint;
var p2 = i + 2 < points.Count ? new Point(points[i + 2].X, points[i + 2].Y) : p1;
var p3 = i + 3 < points.Count ? new Point(points[i + 3].X, points[i + 3].Y) : p2;
var bezierSegment = new BezierSegment(p1, p2, p3, true);
pathFigure.Segments.Add(bezierSegment);
}
pathGeometry.Figures.Add(pathFigure);
return pathGeometry;
}
/// <summary>
/// 将PathGeometry转换为StylusPoint集合
/// </summary>
private List<StylusPoint> ConvertPathGeometryToStylusPoints(PathGeometry pathGeometry, StylusPointCollection originalPoints)
{
var result = new List<StylusPoint>();
var flattened = pathGeometry.GetFlattenedPathGeometry();
foreach (var figure in flattened.Figures)
{
result.Add(new StylusPoint(figure.StartPoint.X, figure.StartPoint.Y, 0.5f));
foreach (var segment in figure.Segments)
{
if (segment is LineSegment lineSegment)
{
result.Add(new StylusPoint(lineSegment.Point.X, lineSegment.Point.Y, 0.5f));
}
else if (segment is PolyLineSegment polyLineSegment)
{
foreach (var point in polyLineSegment.Points)
{
result.Add(new StylusPoint(point.X, point.Y, 0.5f));
}
}
}
}
// 保持原始压感信息
InterpolatePressure(result, originalPoints);
return result;
}
/// <summary>
/// 插值压感信息
/// </summary>
private void InterpolatePressure(List<StylusPoint> smoothedPoints, StylusPointCollection originalPoints)
{
if (originalPoints.Count == 0 || smoothedPoints.Count == 0) return;
for (int i = 0; i < smoothedPoints.Count; i++)
{
double ratio = (double)i / (smoothedPoints.Count - 1);
int originalIndex = (int)(ratio * (originalPoints.Count - 1));
originalIndex = Math.Max(0, Math.Min(originalIndex, originalPoints.Count - 1));
var point = smoothedPoints[i];
float pressure = originalPoints[originalIndex].PressureFactor;
smoothedPoints[i] = new StylusPoint(point.X, point.Y, Math.Max(pressure, 0.1f));
}
}
/// <summary>
/// 使用GPU加速的并行贝塞尔计算
/// </summary>
public static StylusPoint[] ParallelBezierInterpolation(StylusPoint[] controlPoints, int segments = 32)
{
if (controlPoints.Length < 4) return controlPoints;
var result = new StylusPoint[segments * (controlPoints.Length / 4)];
Parallel.For(0, controlPoints.Length / 4, segmentIndex =>
{
var p0 = controlPoints[segmentIndex * 4];
var p1 = controlPoints[segmentIndex * 4 + 1];
var p2 = controlPoints[segmentIndex * 4 + 2];
var p3 = controlPoints[segmentIndex * 4 + 3];
for (int i = 0; i < segments; i++)
{
double t = (double)i / (segments - 1);
result[segmentIndex * segments + i] = CubicBezierFast(p0, p1, p2, p3, t);
}
});
return result;
}
/// <summary>
/// 优化的三次贝塞尔曲线计算
/// </summary>
private static StylusPoint CubicBezierFast(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3, double t)
{
double u = 1 - t;
double tt = t * t;
double uu = u * u;
double uuu = uu * u;
double ttt = tt * t;
double x = uuu * p0.X + 3 * uu * t * p1.X + 3 * u * tt * p2.X + ttt * p3.X;
double y = uuu * p0.Y + 3 * uu * t * p1.Y + 3 * u * tt * p2.Y + ttt * p3.Y;
float pressure = (float)(p1.PressureFactor * u + p2.PressureFactor * t);
return new StylusPoint(x, y, Math.Max(pressure, 0.1f));
}
/// <summary>
/// 释放GPU资源
/// </summary>
public void Dispose()
{
_renderTarget?.Clear();
_isInitialized = false;
}
}
}
+167
View File
@@ -0,0 +1,167 @@
using System;
using System.IO;
using System.Reflection;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// IACore DLL自动释放器
/// 在应用启动时自动释放IACore相关的DLL文件到应用程序目录
/// </summary>
public static class IACoreDllExtractor
{
private static readonly string[] RequiredDlls = {
"IACore.dll",
"IALoader.dll",
"IAWinFX.dll"
};
/// <summary>
/// 在应用启动时释放IACore相关DLL
/// </summary>
public static void ExtractIACoreDlls()
{
try
{
string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
LogHelper.WriteLogToFile("开始检查并释放IACore相关DLL文件");
foreach (string dllName in RequiredDlls)
{
string targetPath = Path.Combine(appDirectory, dllName);
// 检查文件是否已存在且有效
if (File.Exists(targetPath) && IsValidDll(targetPath))
{
LogHelper.WriteLogToFile($"{dllName} 已存在且有效,跳过释放");
continue;
}
// 从嵌入资源中释放DLL
if (ExtractDllFromResource(dllName, targetPath))
{
LogHelper.WriteLogToFile($"成功释放 {dllName} 到 {targetPath}");
}
else
{
LogHelper.WriteLogToFile($"警告:无法释放 {dllName},可能影响形状识别功能", LogHelper.LogType.Warning);
}
}
LogHelper.WriteLogToFile("IACore DLL释放检查完成");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放IACore DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从嵌入资源中提取DLL文件
/// </summary>
private static bool ExtractDllFromResource(string dllName, string targetPath)
{
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
string resourceName = $"Ink_Canvas.Resources.IACore.{dllName}";
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
if (resourceStream == null)
{
LogHelper.WriteLogToFile($"未找到嵌入资源: {resourceName}", LogHelper.LogType.Warning);
return false;
}
// 确保目标目录存在
string targetDirectory = Path.GetDirectoryName(targetPath);
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
// 写入文件
using (FileStream fileStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write))
{
resourceStream.CopyTo(fileStream);
}
return true;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从资源提取 {dllName} 失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 检查DLL文件是否有效
/// </summary>
private static bool IsValidDll(string filePath)
{
try
{
if (!File.Exists(filePath))
return false;
FileInfo fileInfo = new FileInfo(filePath);
// 检查文件大小(空文件或过小的文件可能无效)
if (fileInfo.Length < 1024) // 小于1KB可能无效
return false;
// 简单检查PE头(DLL文件应该以MZ开头)
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[2];
if (fs.Read(buffer, 0, 2) == 2)
{
return buffer[0] == 0x4D && buffer[1] == 0x5A; // "MZ"
}
}
return false;
}
catch
{
return false;
}
}
/// <summary>
/// 清理释放的DLL文件(可选,在应用退出时调用)
/// </summary>
public static void CleanupExtractedDlls()
{
try
{
string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
foreach (string dllName in RequiredDlls)
{
string filePath = Path.Combine(appDirectory, dllName);
if (File.Exists(filePath))
{
try
{
File.Delete(filePath);
LogHelper.WriteLogToFile($"已清理 {dllName}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理 {dllName} 失败: {ex.Message}", LogHelper.LogType.Warning);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理IACore DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
}
@@ -0,0 +1,325 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 改进的三次贝塞尔曲线平滑算法
/// </summary>
public class ImprovedBezierSmoothing
{
private readonly InkSmoothingConfig _config;
public ImprovedBezierSmoothing(InkSmoothingConfig config = null)
{
_config = config ?? new InkSmoothingConfig();
}
/// <summary>
/// 使用改进的贝塞尔曲线算法平滑笔画
/// </summary>
public Stroke SmoothStroke(Stroke originalStroke)
{
if (originalStroke == null || originalStroke.StylusPoints.Count < 3)
return originalStroke;
var originalPoints = originalStroke.StylusPoints.ToArray();
// 预处理:去除噪声点
var cleanedPoints = RemoveNoisePoints(originalPoints);
// 使用改进的贝塞尔曲线拟合
var smoothedPoints = ApplyCubicBezierSmoothing(cleanedPoints);
// 后处理:重采样和优化
var finalPoints = PostProcessPoints(smoothedPoints);
return new Stroke(new StylusPointCollection(finalPoints))
{
DrawingAttributes = originalStroke.DrawingAttributes.Clone()
};
}
/// <summary>
/// 去除噪声点
/// </summary>
private StylusPoint[] RemoveNoisePoints(StylusPoint[] points)
{
if (points.Length < 3) return points;
var result = new List<StylusPoint> { points[0] };
double minDistance = _config.ResampleInterval * 0.5;
for (int i = 1; i < points.Length - 1; i++)
{
var prev = result[result.Count - 1];
var curr = points[i];
var next = points[i + 1];
// 计算到前一个点的距离
double distToPrev = Math.Sqrt((curr.X - prev.X) * (curr.X - prev.X) +
(curr.Y - prev.Y) * (curr.Y - prev.Y));
// 如果距离太近,跳过这个点
if (distToPrev < minDistance)
continue;
// 检查是否为异常点(与前后点形成锐角)
if (IsOutlierPoint(prev, curr, next))
continue;
result.Add(curr);
}
result.Add(points[points.Length - 1]);
return result.ToArray();
}
/// <summary>
/// 检查是否为异常点
/// </summary>
private bool IsOutlierPoint(StylusPoint prev, StylusPoint curr, StylusPoint next)
{
var v1 = new Vector(curr.X - prev.X, curr.Y - prev.Y);
var v2 = new Vector(next.X - curr.X, next.Y - curr.Y);
if (v1.Length == 0 || v2.Length == 0) return false;
v1.Normalize();
v2.Normalize();
double dotProduct = Vector.Multiply(v1, v2);
double angle = Math.Acos(Math.Max(-1, Math.Min(1, dotProduct)));
// 如果角度小于30度,认为是异常点
return angle < Math.PI / 6;
}
/// <summary>
/// 应用三次贝塞尔曲线平滑
/// </summary>
private StylusPoint[] ApplyCubicBezierSmoothing(StylusPoint[] points)
{
if (points.Length < 4) return points;
var result = new List<StylusPoint>();
result.Add(points[0]);
// 使用滑动窗口进行贝塞尔曲线拟合
for (int i = 0; i <= points.Length - 4; i++)
{
var p0 = points[i];
var p1 = points[i + 1];
var p2 = points[i + 2];
var p3 = points[i + 3];
// 计算控制点
var controlPoints = CalculateOptimalControlPoints(p0, p1, p2, p3);
// 计算插值步数
int steps = CalculateInterpolationSteps(p0, p1, p2, p3);
// 生成贝塞尔曲线点
for (int j = 1; j <= steps; j++)
{
double t = (double)j / steps;
var bezierPoint = CalculateBezierPoint(p0, controlPoints.cp1, controlPoints.cp2, p3, t);
result.Add(bezierPoint);
}
}
result.Add(points[points.Length - 1]);
return result.ToArray();
}
/// <summary>
/// 计算最优控制点
/// </summary>
private (Point cp1, Point cp2) CalculateOptimalControlPoints(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3)
{
// 计算切线方向
var tangent1 = CalculateTangent(p0, p1, p2);
var tangent2 = CalculateTangent(p1, p2, p3);
// 计算控制点距离
double dist1 = CalculateDistance(p0, p1);
double dist2 = CalculateDistance(p2, p3);
double controlDist1 = dist1 * _config.CurveTension;
double controlDist2 = dist2 * _config.CurveTension;
// 计算控制点
var cp1 = new Point(
p1.X + tangent1.X * controlDist1,
p1.Y + tangent1.Y * controlDist1
);
var cp2 = new Point(
p2.X - tangent2.X * controlDist2,
p2.Y - tangent2.Y * controlDist2
);
return (cp1, cp2);
}
/// <summary>
/// 计算切线方向
/// </summary>
private Vector CalculateTangent(StylusPoint p0, StylusPoint p1, StylusPoint p2)
{
var v1 = new Vector(p1.X - p0.X, p1.Y - p0.Y);
var v2 = new Vector(p2.X - p1.X, p2.Y - p1.Y);
// 如果向量长度为零,返回零向量
if (v1.Length == 0 || v2.Length == 0)
return new Vector(0, 0);
v1.Normalize();
v2.Normalize();
// 返回平均方向
var tangent = (v1 + v2) / 2;
if (tangent.Length > 0)
tangent.Normalize();
return tangent;
}
/// <summary>
/// 计算两点间距离
/// </summary>
private double CalculateDistance(StylusPoint p1, StylusPoint p2)
{
double dx = p2.X - p1.X;
double dy = p2.Y - p1.Y;
return Math.Sqrt(dx * dx + dy * dy);
}
/// <summary>
/// 计算插值步数
/// </summary>
private int CalculateInterpolationSteps(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3)
{
if (!_config.UseAdaptiveInterpolation)
return _config.InterpolationSteps;
// 计算曲线长度
double totalLength = CalculateDistance(p0, p1) + CalculateDistance(p1, p2) + CalculateDistance(p2, p3);
// 计算曲率
double curvature = CalculateCurvature(p0, p1, p2, p3);
// 基于长度和曲率计算步数
int baseSteps = Math.Max(8, Math.Min(20, (int)(totalLength / 10)));
int curvatureSteps = (int)(curvature * 15);
return Math.Max(_config.InterpolationSteps, Math.Min(30, baseSteps + curvatureSteps));
}
/// <summary>
/// 计算曲率
/// </summary>
private double CalculateCurvature(StylusPoint p0, StylusPoint p1, StylusPoint p2, StylusPoint p3)
{
var v1 = new Vector(p1.X - p0.X, p1.Y - p0.Y);
var v2 = new Vector(p2.X - p1.X, p2.Y - p1.Y);
var v3 = new Vector(p3.X - p2.X, p3.Y - p2.Y);
if (v1.Length == 0 || v2.Length == 0 || v3.Length == 0) return 0;
v1.Normalize();
v2.Normalize();
v3.Normalize();
// 计算角度变化
double angle1 = Math.Acos(Math.Max(-1, Math.Min(1, Vector.Multiply(v1, v2))));
double angle2 = Math.Acos(Math.Max(-1, Math.Min(1, Vector.Multiply(v2, v3))));
return (angle1 + angle2) / Math.PI; // 归一化到0-1
}
/// <summary>
/// 计算贝塞尔曲线上的点
/// </summary>
private StylusPoint CalculateBezierPoint(StylusPoint p0, Point cp1, Point cp2, StylusPoint p3, double t)
{
double u = 1 - t;
double tt = t * t;
double uu = u * u;
double uuu = uu * u;
double ttt = tt * t;
// 预计算系数
double c0 = uuu;
double c1 = 3 * uu * t;
double c2 = 3 * u * tt;
double c3 = ttt;
double x = c0 * p0.X + c1 * cp1.X + c2 * cp2.X + c3 * p3.X;
double y = c0 * p0.Y + c1 * cp1.Y + c2 * cp2.Y + c3 * p3.Y;
// 插值压力值
float pressure = (float)(p0.PressureFactor * u + p3.PressureFactor * t);
pressure = Math.Max(pressure, 0.1f);
return new StylusPoint(x, y, pressure);
}
/// <summary>
/// 后处理点集
/// </summary>
private StylusPoint[] PostProcessPoints(StylusPoint[] points)
{
if (points.Length == 0) return points;
// 如果点数过多,进行重采样
if (points.Length > _config.MaxPointsPerStroke)
{
return ResamplePoints(points, _config.ResampleInterval);
}
return points;
}
/// <summary>
/// 重采样点集
/// </summary>
private StylusPoint[] ResamplePoints(StylusPoint[] points, double interval)
{
var result = new List<StylusPoint> { points[0] };
double accumulated = 0;
for (int i = 1; i < points.Length; i++)
{
var prev = result[result.Count - 1];
var curr = points[i];
double dx = curr.X - prev.X;
double dy = curr.Y - prev.Y;
double dist = Math.Sqrt(dx * dx + dy * dy);
if (dist + accumulated >= interval)
{
double t = (interval - accumulated) / dist;
double x = prev.X + t * dx;
double y = prev.Y + t * dy;
float pressure = (float)(prev.PressureFactor * (1 - t) + curr.PressureFactor * t);
pressure = Math.Max(pressure, 0.1f);
result.Add(new StylusPoint(x, y, pressure));
accumulated = 0;
i--; // 重新处理当前点
}
else
{
accumulated += dist;
}
}
return result.ToArray();
}
}
}
+897
View File
@@ -0,0 +1,897 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 墨迹渐隐管理器 - 管理墨迹的渐隐动画和状态
/// </summary>
public class InkFadeManager
{
#region Properties
/// <summary>
/// 是否启用墨迹渐隐功能
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// 墨迹渐隐时间(毫秒)
/// </summary>
public int FadeTime { get; set; } = 3000;
/// <summary>
/// 渐隐动画持续时间(毫秒)
/// </summary>
public int AnimationDuration { get; set; } = 1000;
#endregion
#region Private Fields
private readonly MainWindow _mainWindow;
private readonly Dispatcher _dispatcher;
private readonly Dictionary<Stroke, DispatcherTimer> _fadeTimers;
private readonly Dictionary<Stroke, UIElement> _strokeVisuals;
private readonly Dictionary<Stroke, Point> _strokeStartPoints;
private readonly Dictionary<Stroke, Point> _strokeEndPoints;
#endregion
#region Constructor
public InkFadeManager(MainWindow mainWindow)
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
_dispatcher = _mainWindow.Dispatcher;
_fadeTimers = new Dictionary<Stroke, DispatcherTimer>();
_strokeVisuals = new Dictionary<Stroke, UIElement>();
_strokeStartPoints = new Dictionary<Stroke, Point>();
_strokeEndPoints = new Dictionary<Stroke, Point>();
}
#endregion
#region Public Methods
/// <summary>
/// 添加需要渐隐的墨迹
/// </summary>
/// <param name="stroke">墨迹对象</param>
/// <param name="startPoint">落笔点</param>
/// <param name="endPoint">抬笔点</param>
public void AddFadingStroke(Stroke stroke, Point startPoint, Point endPoint)
{
if (!IsEnabled || stroke == null)
{
return;
}
try
{
// 确保主窗口的InkCanvas保持Ink编辑模式,防止墨迹渐隐时切换到鼠标模式
if (_mainWindow.inkCanvas.EditingMode != InkCanvasEditingMode.Ink)
{
_mainWindow.inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
// 记录墨迹的起点和终点
_strokeStartPoints[stroke] = startPoint;
_strokeEndPoints[stroke] = endPoint;
// 创建墨迹的视觉元素(湿墨迹状态)
var strokeVisual = CreateStrokeVisual(stroke);
if (strokeVisual == null) return;
_strokeVisuals[stroke] = strokeVisual;
// 创建定时器,在指定时间后开始渐隐动画
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(FadeTime)
};
timer.Tick += (sender, e) =>
{
StartFadeAnimation(stroke);
timer.Stop();
_fadeTimers.Remove(stroke);
};
_fadeTimers[stroke] = timer;
timer.Start();
// 将视觉元素添加到画布上
_dispatcher.InvokeAsync(() =>
{
try
{
if (_mainWindow.inkCanvas != null)
{
// 将墨迹添加到 inkCanvas 的父容器中,而不是 inkCanvas.Children
// 这样可以避免坐标系统问题
var parent = _mainWindow.inkCanvas.Parent as Panel;
if (parent != null)
{
parent.Children.Add(strokeVisual);
}
else
{
// 如果无法获取父容器,则添加到 inkCanvas.Children
_mainWindow.inkCanvas.Children.Add(strokeVisual);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加墨迹视觉元素到画布失败: {ex}", LogHelper.LogType.Error);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 移除墨迹
/// </summary>
/// <param name="stroke">要移除的墨迹</param>
public void RemoveStroke(Stroke stroke)
{
if (stroke == null) return;
try
{
if (_fadeTimers.TryGetValue(stroke, out var timer))
{
timer.Stop();
_fadeTimers.Remove(stroke);
}
if (_strokeVisuals.TryGetValue(stroke, out var visual))
{
_dispatcher.InvokeAsync(() =>
{
try
{
// 从父容器中移除墨迹
var parent = _mainWindow.inkCanvas?.Parent as Panel;
if (parent != null && parent.Children.Contains(visual))
{
parent.Children.Remove(visual);
}
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从画布移除墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
}
});
_strokeVisuals.Remove(stroke);
}
_strokeStartPoints.Remove(stroke);
_strokeEndPoints.Remove(stroke);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"移除渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 清除所有渐隐墨迹
/// </summary>
public void ClearAllFadingStrokes()
{
try
{
foreach (var timer in _fadeTimers.Values)
{
timer.Stop();
}
_fadeTimers.Clear();
_dispatcher.InvokeAsync(() =>
{
try
{
if (_mainWindow.inkCanvas != null)
{
var parent = _mainWindow.inkCanvas.Parent as Panel;
foreach (var visual in _strokeVisuals.Values)
{
if (parent != null && parent.Children.Contains(visual))
{
parent.Children.Remove(visual);
}
else if (_mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除所有墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
}
});
_strokeVisuals.Clear();
_strokeStartPoints.Clear();
_strokeEndPoints.Clear();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除所有渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 更新渐隐时间设置
/// </summary>
/// <param name="fadeTime">新的渐隐时间(毫秒)</param>
public void UpdateFadeTime(int fadeTime)
{
FadeTime = fadeTime;
foreach (var kvp in _fadeTimers)
{
var stroke = kvp.Key;
var timer = kvp.Value;
timer.Stop();
timer.Interval = TimeSpan.FromMilliseconds(FadeTime);
timer.Start();
}
}
/// <summary>
/// 启用墨迹渐隐功能
/// </summary>
public void Enable()
{
IsEnabled = true;
LogHelper.WriteLogToFile("墨迹渐隐功能已启用");
}
/// <summary>
/// 禁用墨迹渐隐功能
/// </summary>
public void Disable()
{
IsEnabled = false;
LogHelper.WriteLogToFile("墨迹渐隐功能已禁用");
}
#endregion
#region Private Methods
/// <summary>
/// 创建墨迹的视觉元素
/// </summary>
/// <param name="stroke">墨迹对象</param>
/// <returns>视觉元素</returns>
private UIElement CreateStrokeVisual(Stroke stroke)
{
try
{
// 创建路径几何,使用墨迹的实际位置
var geometry = stroke.GetGeometry();
if (geometry == null)
{
return null;
}
// 获取绘画属性
var drawingAttribs = stroke.DrawingAttributes;
// 创建路径元素,确保使用正确的绘画属性
var path = new Path
{
Data = geometry,
Stroke = new SolidColorBrush(drawingAttribs.Color),
StrokeThickness = drawingAttribs.Width, // 使用原始墨迹的粗细
StrokeStartLineCap = PenLineCap.Round,
StrokeEndLineCap = PenLineCap.Round,
StrokeLineJoin = PenLineJoin.Round,
Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null, // 高亮笔需要填充
Opacity = 0.95, // 初始透明度更高,显得更自然
// 优化渲染质量
UseLayoutRounding = false,
SnapsToDevicePixels = false
};
// 如果是高亮笔,调整透明度和混合模式
if (drawingAttribs.IsHighlighter)
{
path.Opacity = 0.4; // 高亮笔初始透明度更低,更符合荧光笔特性
// 为高亮笔添加特殊的混合效果
// 使用更柔和的笔触样式
path.StrokeStartLineCap = PenLineCap.Flat;
path.StrokeEndLineCap = PenLineCap.Flat;
path.StrokeLineJoin = PenLineJoin.Miter;
// 高亮笔通常需要更宽的笔触来覆盖下面的内容
if (drawingAttribs.Width < 20)
{
path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
}
// 为高亮笔添加轻微的模糊效果,使渐隐更加自然
path.Effect = new BlurEffect
{
Radius = 0.5, // 轻微的模糊效果
KernelType = KernelType.Gaussian
};
}
// 不设置任何变换,保持墨迹原有粗细
var bounds = geometry.Bounds;
// 设置墨迹的初始位置
System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
return path;
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// 开始渐隐动画
/// </summary>
/// <param name="stroke">要渐隐的墨迹</param>
private void StartFadeAnimation(Stroke stroke)
{
if (!_strokeVisuals.TryGetValue(stroke, out var visual)) return;
try
{
_dispatcher.InvokeAsync(() =>
{
// 获取当前透明度和判断是否为高亮笔
var currentOpacity = visual.Opacity;
var isHighlighter = stroke.DrawingAttributes.IsHighlighter;
// 根据墨迹类型选择不同的动画效果
if (isHighlighter)
{
StartHighlighterFadeAnimation(visual, stroke, currentOpacity);
}
else
{
StartNormalStrokeFadeAnimation(visual, stroke, currentOpacity);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"开始渐隐动画失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 开始普通墨迹的渐隐动画
/// </summary>
private void StartNormalStrokeFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
{
try
{
StartProgressiveFadeAnimation(visual, stroke, currentOpacity, AnimationDuration);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"开始普通墨迹渐隐动画失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 统一渐隐动画 - 整个墨迹作为一个整体进行渐隐,与擦除效果一致
/// </summary>
private void StartUnifiedFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
{
try
{
// 创建透明度动画,模拟擦除时的效果
var fadeAnimation = new DoubleAnimation
{
From = currentOpacity,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(duration),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
};
// 如果是高亮笔,添加轻微的缩放效果,使渐隐更加自然
if (stroke.DrawingAttributes.IsHighlighter)
{
// 创建轻微的缩放动画,模拟墨迹"蒸发"的效果
var scaleAnimation = new DoubleAnimation
{
From = 1.0,
To = 0.95, // 轻微缩小,增加自然感
Duration = TimeSpan.FromMilliseconds(duration),
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseIn }
};
// 创建缩放变换
var scaleTransform = new ScaleTransform();
visual.RenderTransform = scaleTransform;
visual.RenderTransformOrigin = new Point(0.5, 0.5);
// 应用缩放动画
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
}
// 添加动画完成事件
fadeAnimation.Completed += (sender, e) => OnAnimationCompleted(visual, stroke);
// 应用透明度动画
visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"统一渐隐动画失败: {ex}", LogHelper.LogType.Error);
OnAnimationCompleted(visual, stroke);
}
}
/// <summary>
/// 开始高亮笔的渐隐动画
/// </summary>
private void StartHighlighterFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
{
try
{
// 高亮笔使用统一的渐隐动画,与擦除效果一致
StartUnifiedFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.2));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"开始高亮笔渐隐动画失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 渐进式渐隐动画 - 从起点到终点逐渐消失
/// </summary>
private void StartProgressiveFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
{
try
{
// 确保所有墨迹都能显示动画,包括短墨迹
if (stroke.StylusPoints.Count < 2)
{
// 只有1个点的墨迹也使用分段动画,确保视觉效果
CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
return;
}
// 将墨迹分段并创建多个 Path
CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"渐进式渐隐动画失败: {ex}", LogHelper.LogType.Error);
// 失败时回退到简单动画
StartSimpleFadeAnimation(visual, stroke, currentOpacity, duration);
}
}
/// <summary>
/// 创建分段墨迹并开始渐进消失
/// </summary>
private void CreateSegmentedStroke(UIElement originalVisual, Stroke stroke, double opacity, int duration)
{
try
{
var stylusPoints = stroke.StylusPoints;
var totalPoints = stylusPoints.Count;
// 分段算法 - 确保所有墨迹都有足够的动画效果
var strokeLength = CalculateStrokeLength(stylusPoints);
var segmentCount = CalculateOptimalSegmentCount(totalPoints, strokeLength);
// 强制最小分段数量,确保短墨迹也有动画效果
segmentCount = Math.Max(segmentCount, 4);
var pointsPerSegment = Math.Max(1, totalPoints / segmentCount);
// 隐藏原始视觉元素
originalVisual.Visibility = Visibility.Hidden;
var segments = new List<UIElement>();
var parent = _mainWindow.inkCanvas?.Parent as Panel;
if (parent == null)
{
// 如果父容器不是Panel,直接使用InkCanvas
parent = null; // 稍后会检查并使用InkCanvas.Children
}
// 创建各个分段 - 确保短墨迹也能正确分段
for (int i = 0; i < segmentCount; i++)
{
var startIndex = i * pointsPerSegment;
var endIndex = (i == segmentCount - 1) ? totalPoints - 1 : (i + 1) * pointsPerSegment;
// 确保有足够的点来创建分段,对于短墨迹特殊处理
if (endIndex <= startIndex && totalPoints > 1)
{
// 短墨迹:每个点作为一个分段
startIndex = i;
endIndex = Math.Min(i + 1, totalPoints - 1);
}
// 为每个分段添加重叠,确保连接处平滑
var overlap = Math.Max(1, pointsPerSegment / 6); // 15%的重叠,平衡平滑与速度
var actualStartIndex = Math.Max(0, startIndex - overlap);
var actualEndIndex = Math.Min(totalPoints - 1, endIndex + overlap);
var segment = CreateStrokeSegment(stroke, actualStartIndex, actualEndIndex, opacity);
if (segment != null)
{
segments.Add(segment);
if (parent != null)
{
parent.Children.Add(segment);
}
else if (_mainWindow.inkCanvas != null)
{
_mainWindow.inkCanvas.Children.Add(segment);
}
}
}
// 开始分段渐隐动画
StartSegmentedFadeAnimation(segments, stroke, originalVisual, duration);
}
catch (Exception)
{
StartSimpleFadeAnimation(originalVisual, stroke, opacity, duration);
}
}
/// <summary>
/// 创建墨迹分段
/// </summary>
private UIElement CreateStrokeSegment(Stroke originalStroke, int startIndex, int endIndex, double opacity)
{
try
{
// 创建分段的 StylusPoint 集合
var segmentPoints = new StylusPointCollection();
for (int i = startIndex; i <= endIndex && i < originalStroke.StylusPoints.Count; i++)
{
segmentPoints.Add(originalStroke.StylusPoints[i]);
}
if (segmentPoints.Count < 2) return null;
// 创建分段墨迹
var segmentStroke = new Stroke(segmentPoints)
{
DrawingAttributes = originalStroke.DrawingAttributes.Clone()
};
// 创建分段的视觉元素
var geometry = segmentStroke.GetGeometry();
if (geometry == null) return null;
var drawingAttribs = segmentStroke.DrawingAttributes;
var path = new Path
{
Data = geometry,
Stroke = new SolidColorBrush(drawingAttribs.Color),
StrokeThickness = drawingAttribs.Width,
StrokeStartLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
StrokeEndLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
StrokeLineJoin = drawingAttribs.IsHighlighter ? PenLineJoin.Miter : PenLineJoin.Round,
Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null,
Opacity = opacity,
UseLayoutRounding = false,
SnapsToDevicePixels = false
};
// 设置位置
var bounds = geometry.Bounds;
System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
return path;
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// 开始分段渐隐动画
/// </summary>
private void StartSegmentedFadeAnimation(List<UIElement> segments, Stroke originalStroke, UIElement originalVisual, int totalDuration)
{
try
{
// 动画时序算法
var segmentDuration = CalculateOptimalSegmentDuration(totalDuration, segments.Count);
var animationCurve = CreateAppleStyleAnimationCurve(segments.Count, totalDuration);
// 跟踪动画完成状态
var completedSegments = new HashSet<UIElement>();
var totalSegments = segments.Count;
// 渐隐效果 - 使用自然的动画曲线
for (int i = 0; i < segments.Count; i++)
{
var segment = segments[i];
// 使用预计算的动画曲线获取延迟时间
var delay = animationCurve[i];
// 使用定时器延迟启动每个分段的动画
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(delay)
};
int segmentIndex = i; // 捕获当前索引
timer.Tick += (sender, e) =>
{
StartSingleSegmentFadeAnimation(segment, segmentDuration, () =>
{
// 动画完成回调
lock (completedSegments)
{
completedSegments.Add(segment);
// 检查是否所有分段都完成了
if (completedSegments.Count >= totalSegments)
{
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
}
}
});
timer.Stop();
};
timer.Start();
}
// 设置一个安全超时定时器,防止无限等待
var safetyTimeout = totalDuration + (segments.Count * segmentDuration) + 1200; // 额外1.2秒缓冲,确保动画完整
var safetyTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(safetyTimeout)
};
safetyTimer.Tick += (sender, e) =>
{
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
safetyTimer.Stop();
};
safetyTimer.Start();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
}
}
/// <summary>
/// 单个分段的渐隐动画
/// </summary>
private void StartSingleSegmentFadeAnimation(UIElement segment, int duration, Action onCompleted = null)
{
try
{
// 只使用透明度动画,保持墨迹原有粗细
var fadeAnimation = new DoubleAnimation
{
From = segment.Opacity,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(duration),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } // 更平滑的缓动
};
// 添加动画完成事件
if (onCompleted != null)
{
fadeAnimation.Completed += (sender, e) =>
{
onCompleted?.Invoke();
};
}
// 只应用透明度动画,不改变墨迹大小
segment.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"单个分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
// 即使失败也要调用完成回调
onCompleted?.Invoke();
}
}
/// <summary>
/// 清理分段动画
/// </summary>
private void CleanupSegmentedAnimation(List<UIElement> segments, Stroke originalStroke, UIElement originalVisual)
{
try
{
// 移除所有分段
var parent = _mainWindow.inkCanvas?.Parent as Panel;
foreach (var segment in segments)
{
if (parent != null && parent.Children.Contains(segment))
{
parent.Children.Remove(segment);
}
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(segment))
{
_mainWindow.inkCanvas.Children.Remove(segment);
}
}
// 清理原始墨迹
OnAnimationCompleted(originalVisual, originalStroke);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理分段动画失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 简单渐隐动画(备用方案)
/// </summary>
private void StartSimpleFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
{
try
{
var fadeAnimation = new DoubleAnimation
{
From = currentOpacity,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(duration),
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseIn }
};
fadeAnimation.Completed += (sender, e) => OnAnimationCompleted(visual, stroke);
visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"简单渐隐动画失败: {ex}", LogHelper.LogType.Error);
OnAnimationCompleted(visual, stroke);
}
}
/// <summary>
/// 计算墨迹的实际长度
/// </summary>
private double CalculateStrokeLength(StylusPointCollection points)
{
if (points.Count < 2) return 0;
double totalLength = 0;
for (int i = 1; i < points.Count; i++)
{
var p1 = points[i - 1].ToPoint();
var p2 = points[i].ToPoint();
totalLength += Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
}
return totalLength;
}
/// <summary>
/// 根据墨迹特性计算最优分段数量 - 平衡速度与完整性
/// </summary>
private int CalculateOptimalSegmentCount(int pointCount, double strokeLength)
{
// 平衡速度与完整性,确保动画效果的同时提高速度
const double PIXELS_PER_SEGMENT = 12.0; // 每段适中长度,平衡效果与速度
const int MIN_SEGMENTS = 5; // 适当的最小分段数,确保动画效果
const int MAX_SEGMENTS = 100; // 适中的最大分段数,平衡性能与效果
// 根据长度计算基础分段数
var lengthBasedSegments = Math.Max(MIN_SEGMENTS, (int)(strokeLength / PIXELS_PER_SEGMENT));
// 根据点密度调整,平衡效果与速度
var density = pointCount > 0 ? strokeLength / pointCount : 1;
var densityFactor = Math.Max(0.4, Math.Min(2.5, density / 1.8));
var finalSegments = (int)(lengthBasedSegments * densityFactor);
// 对于短墨迹,确保至少有4个分段
if (pointCount <= 5)
{
finalSegments = Math.Max(finalSegments, 4);
}
// 限制在合理范围内
return Math.Min(MAX_SEGMENTS, Math.Max(MIN_SEGMENTS, finalSegments));
}
/// <summary>
/// 计算最优的单段动画持续时间 - 平衡速度与完整性
/// </summary>
private int CalculateOptimalSegmentDuration(int totalDuration, int segmentCount)
{
// 平衡速度与动画完整性
var baseDuration = totalDuration / Math.Max(segmentCount, 1);
var minDuration = 150; // 每段最少150ms,确保动画完整显示
var maxDuration = 500; // 每段最多500ms,平衡速度与完整性
return Math.Max(minDuration, Math.Min(maxDuration, baseDuration));
}
/// <summary>
/// 创建优化的动画时间曲线 - 平衡速度与完整性
/// </summary>
private int[] CreateAppleStyleAnimationCurve(int segmentCount, int totalDuration)
{
var curve = new int[segmentCount];
// 平衡速度与完整性,确保动画有足够时间播放
var availableTime = totalDuration * 0.6; // 使用60%的总时间,给动画留足够缓冲
var delayBetweenSegments = Math.Max(60, availableTime / Math.Max(segmentCount, 1));
for (int i = 0; i < segmentCount; i++)
{
// 线性延迟,确保每个分段都有足够时间
curve[i] = (int)(i * delayBetweenSegments);
}
return curve;
}
/// <summary>
/// 动画完成后的统一处理
/// </summary>
private void OnAnimationCompleted(UIElement visual, Stroke stroke)
{
try
{
// 从父容器中移除墨迹
var parent = _mainWindow.inkCanvas?.Parent as Panel;
if (parent != null && parent.Children.Contains(visual))
{
parent.Children.Remove(visual);
}
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
RemoveStroke(stroke);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
#endregion
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Ink_Canvas.Helpers
var analyzer = new InkAnalyzer();
analyzer.AddStrokes(strokes);
analyzer.SetStrokesType(strokes, System.Windows.Ink.StrokeType.Drawing);
analyzer.SetStrokesType(strokes, StrokeType.Drawing);
AnalysisAlternate analysisAlternate = null;
int strokesCount = strokes.Count;
+164
View File
@@ -0,0 +1,164 @@
using System;
using System.Diagnostics;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 墨迹平滑配置类
/// </summary>
public class InkSmoothingConfig
{
// 基本平滑参数
public double SmoothingStrength { get; set; } = 0.4;
public double ResampleInterval { get; set; } = 2.5;
public int InterpolationSteps { get; set; } = 12;
// 贝塞尔曲线参数
public bool UseAdaptiveInterpolation { get; set; } = true;
public double CurveTension { get; set; } = 0.3;
public double MinCurvatureThreshold { get; set; } = 0.1;
public double MaxCurvatureThreshold { get; set; } = 0.8;
// 性能参数
public bool UseHardwareAcceleration { get; set; } = true;
public bool UseAsyncProcessing { get; set; } = true;
public int MaxConcurrentTasks { get; set; } = Environment.ProcessorCount;
public int MaxPointsPerStroke { get; set; } = 10000;
// 质量设置
public SmoothingQuality Quality { get; set; } = SmoothingQuality.Balanced;
public enum SmoothingQuality
{
Performance, // 性能优先
Balanced, // 平衡
Quality // 质量优先
}
// 兼容性枚举
public enum InkSmoothingQuality
{
HighPerformance = 0, // 高性能低质量
Balanced = 1, // 平衡
HighQuality = 2 // 高质量低性能
}
/// <summary>
/// 从设置中加载配置
/// </summary>
public static InkSmoothingConfig FromSettings()
{
var config = new InkSmoothingConfig();
try
{
// 尝试从MainWindow.Settings加载配置(兼容性)
if (MainWindow.Settings?.Canvas != null)
{
config.Quality = (SmoothingQuality)MainWindow.Settings.Canvas.InkSmoothingQuality;
config.UseHardwareAcceleration = MainWindow.Settings.Canvas.UseHardwareAcceleration;
config.UseAsyncProcessing = MainWindow.Settings.Canvas.UseAsyncInkSmoothing;
config.MaxConcurrentTasks = MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks > 0 ?
MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks : Environment.ProcessorCount;
}
}
catch (Exception ex)
{
Debug.WriteLine($"加载平滑配置失败: {ex.Message}");
}
return config;
}
/// <summary>
/// 应用质量设置
/// </summary>
public void ApplyQualitySettings()
{
// 保存用户设置的异步处理偏好
bool userAsyncPreference = UseAsyncProcessing;
switch (Quality)
{
case SmoothingQuality.Performance:
SmoothingStrength = 0.15;
ResampleInterval = 5.0;
InterpolationSteps = 4;
UseAdaptiveInterpolation = false;
CurveTension = 0.15;
MaxConcurrentTasks = Math.Max(1, Environment.ProcessorCount / 2);
UseHardwareAcceleration = true;
UseAsyncProcessing = userAsyncPreference;
break;
case SmoothingQuality.Balanced:
SmoothingStrength = 0.3;
ResampleInterval = 3.0;
InterpolationSteps = 8;
UseAdaptiveInterpolation = true;
CurveTension = 0.25;
MaxConcurrentTasks = Environment.ProcessorCount;
UseHardwareAcceleration = true;
UseAsyncProcessing = userAsyncPreference;
break;
case SmoothingQuality.Quality:
SmoothingStrength = 0.5;
ResampleInterval = 2.0;
InterpolationSteps = 15;
UseAdaptiveInterpolation = true;
CurveTension = 0.35;
MaxConcurrentTasks = Environment.ProcessorCount;
UseHardwareAcceleration = true;
UseAsyncProcessing = userAsyncPreference;
break;
}
}
/// <summary>
/// 保存配置到设置
/// </summary>
public void SaveToSettings()
{
try
{
// 尝试保存到MainWindow.Settings(兼容性)
if (MainWindow.Settings?.Canvas != null)
{
MainWindow.Settings.Canvas.InkSmoothingQuality = (int)Quality;
MainWindow.Settings.Canvas.UseHardwareAcceleration = UseHardwareAcceleration;
MainWindow.Settings.Canvas.UseAsyncInkSmoothing = UseAsyncProcessing;
MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks = MaxConcurrentTasks;
}
}
catch (Exception ex)
{
Debug.WriteLine($"保存平滑配置失败: {ex.Message}");
}
}
/// <summary>
/// 验证配置参数
/// </summary>
public bool Validate()
{
return SmoothingStrength >= 0.0 && SmoothingStrength <= 1.0 &&
ResampleInterval > 0.0 &&
InterpolationSteps > 0 && InterpolationSteps <= 50 &&
CurveTension >= 0.0 && CurveTension <= 1.0 &&
MaxConcurrentTasks > 0 &&
MaxPointsPerStroke > 0;
}
/// <summary>
/// 获取配置摘要
/// </summary>
public string GetSummary()
{
return $"质量: {Quality}, 强度: {SmoothingStrength:F2}, 间隔: {ResampleInterval:F1}, " +
$"步数: {InterpolationSteps}, 自适应: {UseAdaptiveInterpolation}, " +
$"张力: {CurveTension:F2}, 硬件加速: {UseHardwareAcceleration}";
}
}
}
+262
View File
@@ -0,0 +1,262 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Ink;
using System.Windows.Media;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 统一的墨迹平滑管理器,整合异步处理和硬件加速
/// </summary>
public class InkSmoothingManager : IDisposable
{
private readonly AsyncAdvancedBezierSmoothing _asyncSmoothing;
private readonly HardwareAcceleratedInkProcessor _hardwareProcessor;
private readonly InkSmoothingPerformanceMonitor _performanceMonitor;
private readonly InkSmoothingConfig _config;
private readonly Dispatcher _uiDispatcher;
private bool _disposed;
public InkSmoothingManager(Dispatcher uiDispatcher)
{
_uiDispatcher = uiDispatcher;
_config = InkSmoothingConfig.FromSettings();
_config.ApplyQualitySettings();
_asyncSmoothing = new AsyncAdvancedBezierSmoothing(uiDispatcher)
{
SmoothingStrength = _config.SmoothingStrength,
ResampleInterval = _config.ResampleInterval,
InterpolationSteps = _config.InterpolationSteps,
UseHardwareAcceleration = _config.UseHardwareAcceleration,
MaxConcurrentTasks = _config.MaxConcurrentTasks
};
_hardwareProcessor = new HardwareAcceleratedInkProcessor();
_performanceMonitor = new InkSmoothingPerformanceMonitor();
}
/// <summary>
/// 平滑笔画(自动选择最佳方法)
/// </summary>
public async Task<Stroke> SmoothStrokeAsync(Stroke originalStroke,
Action<Stroke, Stroke> onCompleted = null,
CancellationToken cancellationToken = default)
{
if (originalStroke == null || originalStroke.StylusPoints.Count < 2)
return originalStroke;
var stopwatch = Stopwatch.StartNew();
Stroke result = originalStroke;
try
{
if (_config.UseAsyncProcessing)
{
// 使用异步处理
result = await _asyncSmoothing.SmoothStrokeAsync(originalStroke, onCompleted, cancellationToken);
}
else if (_config.UseHardwareAcceleration)
{
// 使用硬件加速但同步处理
result = await _hardwareProcessor.SmoothStrokeWithGPU(originalStroke);
onCompleted?.Invoke(originalStroke, result);
}
else
{
// 回退到传统同步处理
result = await Task.Run(() =>
{
var traditionalSmoothing = new AdvancedBezierSmoothing();
return traditionalSmoothing.SmoothStroke(originalStroke);
}, cancellationToken);
onCompleted?.Invoke(originalStroke, result);
}
}
catch (OperationCanceledException)
{
result = originalStroke;
}
catch (Exception ex)
{
Debug.WriteLine($"墨迹平滑失败: {ex.Message}");
result = originalStroke;
}
finally
{
stopwatch.Stop();
_performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
}
return result;
}
/// <summary>
/// 同步平滑笔画(用于向后兼容)
/// </summary>
public Stroke SmoothStroke(Stroke originalStroke)
{
if (originalStroke == null || originalStroke.StylusPoints.Count < 2)
return originalStroke;
var stopwatch = Stopwatch.StartNew();
Stroke result;
try
{
if (_config.UseHardwareAcceleration)
{
// 使用硬件加速的同步版本
var task = _hardwareProcessor.SmoothStrokeWithGPU(originalStroke);
task.Wait(5000); // 5秒超时
result = task.Status == TaskStatus.RanToCompletion ? task.Result : originalStroke;
}
else
{
// 传统同步处理
var traditionalSmoothing = new AdvancedBezierSmoothing();
result = traditionalSmoothing.SmoothStroke(originalStroke);
}
}
catch (Exception ex)
{
Debug.WriteLine($"同步墨迹平滑失败: {ex.Message}");
result = originalStroke;
}
finally
{
stopwatch.Stop();
_performanceMonitor.RecordProcessingTime(stopwatch.Elapsed);
}
return result;
}
/// <summary>
/// 更新配置
/// </summary>
public void UpdateConfig()
{
var newConfig = InkSmoothingConfig.FromSettings();
newConfig.ApplyQualitySettings();
_asyncSmoothing.SmoothingStrength = newConfig.SmoothingStrength;
_asyncSmoothing.ResampleInterval = newConfig.ResampleInterval;
_asyncSmoothing.InterpolationSteps = newConfig.InterpolationSteps;
_asyncSmoothing.UseHardwareAcceleration = newConfig.UseHardwareAcceleration;
_asyncSmoothing.MaxConcurrentTasks = newConfig.MaxConcurrentTasks;
}
/// <summary>
/// 获取性能统计信息
/// </summary>
public string GetPerformanceStats()
{
return $"平均处理时间: {_performanceMonitor.GetAverageProcessingTimeMs():F2}ms, " +
$"最大处理时间: {_performanceMonitor.GetMaxProcessingTimeMs():F2}ms, " +
$"样本数: {_performanceMonitor.GetSampleCount()}";
}
/// <summary>
/// 取消所有正在进行的任务
/// </summary>
public void CancelAllTasks()
{
_asyncSmoothing?.CancelAllTasks();
}
/// <summary>
/// 检查系统是否支持硬件加速
/// </summary>
public static bool IsHardwareAccelerationSupported()
{
try
{
return RenderCapability.Tier >= 0x00020000;
}
catch
{
return false;
}
}
/// <summary>
/// 获取推荐的配置
/// </summary>
public static InkSmoothingConfig GetRecommendedConfig()
{
var config = new InkSmoothingConfig();
// 根据系统性能调整配置
var processorCount = Environment.ProcessorCount;
var isHardwareAccelerated = IsHardwareAccelerationSupported();
if (processorCount >= 4 && isHardwareAccelerated)
{
// 降低高质量模式的门槛,4核以上且支持硬件加速就使用高质量
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.HighQuality;
config.UseHardwareAcceleration = true;
config.UseAsyncProcessing = true;
config.MaxConcurrentTasks = Math.Min(processorCount, 8);
}
else if (processorCount >= 2)
{
// 2核以上使用平衡模式
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.Balanced;
config.UseHardwareAcceleration = isHardwareAccelerated;
config.UseAsyncProcessing = true;
config.MaxConcurrentTasks = Math.Min(processorCount, 4);
}
else
{
// 单核或性能较低的设备使用高性能模式
config.Quality = (InkSmoothingConfig.SmoothingQuality)InkSmoothingConfig.InkSmoothingQuality.HighPerformance;
config.UseHardwareAcceleration = false;
config.UseAsyncProcessing = false;
config.MaxConcurrentTasks = 1;
}
config.ApplyQualitySettings();
return config;
}
/// <summary>
/// 应用推荐配置到设置
/// </summary>
public static void ApplyRecommendedSettings()
{
var config = GetRecommendedConfig();
MainWindow.Settings.Canvas.InkSmoothingQuality = (int)config.Quality;
MainWindow.Settings.Canvas.UseHardwareAcceleration = config.UseHardwareAcceleration;
MainWindow.Settings.Canvas.UseAsyncInkSmoothing = config.UseAsyncProcessing;
MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks = config.MaxConcurrentTasks;
}
public void Dispose()
{
if (!_disposed)
{
CancelAllTasks();
_asyncSmoothing?.Dispose();
_hardwareProcessor?.Dispose();
_disposed = true;
}
}
}
/// <summary>
/// 墨迹平滑事件参数
/// </summary>
public class InkSmoothingEventArgs : EventArgs
{
public Stroke OriginalStroke { get; set; }
public Stroke SmoothedStroke { get; set; }
public TimeSpan ProcessingTime { get; set; }
public bool WasAsync { get; set; }
public bool UsedHardwareAcceleration { get; set; }
}
}
+16 -12
View File
@@ -1,32 +1,36 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Interop;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using Point = System.Windows.Point;
namespace Ink_Canvas.Helpers {
internal class IsOutsideOfScreenHelper {
public static bool IsOutsideOfScreen(FrameworkElement target) {
namespace Ink_Canvas.Helpers
{
internal class IsOutsideOfScreenHelper
{
public static bool IsOutsideOfScreen(FrameworkElement target)
{
var hwndSource = (HwndSource)PresentationSource.FromVisual(target);
if (hwndSource is null) {
if (hwndSource is null)
{
return true;
}
var hWnd = hwndSource.Handle;
var targetBounds = GetPixelBoundsToScreen(target);
var screens = System.Windows.Forms.Screen.AllScreens;
var screens = Screen.AllScreens;
return !screens.Any(x => x.Bounds.IntersectsWith(targetBounds));
System.Drawing.Rectangle GetPixelBoundsToScreen(FrameworkElement visual) {
Rectangle GetPixelBoundsToScreen(FrameworkElement visual)
{
var pixelBoundsToScreen = Rect.Empty;
pixelBoundsToScreen.Union(visual.PointToScreen(new Point(0, 0)));
pixelBoundsToScreen.Union(visual.PointToScreen(new Point(visual.ActualWidth, 0)));
pixelBoundsToScreen.Union(visual.PointToScreen(new Point(0, visual.ActualHeight)));
pixelBoundsToScreen.Union(visual.PointToScreen(new Point(visual.ActualWidth, visual.ActualHeight)));
return new System.Drawing.Rectangle(
return new Rectangle(
(int)pixelBoundsToScreen.X, (int)pixelBoundsToScreen.Y,
(int)pixelBoundsToScreen.Width, (int)pixelBoundsToScreen.Height);
}
+70 -2
View File
@@ -8,10 +8,13 @@ namespace Ink_Canvas.Helpers
class LogHelper
{
public static string LogFile = "Log.txt";
private static string LogsFolder = "Logs";
private static string AppStartTime = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss");
private static readonly long MaxLogsFolderSizeBytes = 5 * 1024 * 1024; // 5MB
public static void NewLog(string str)
{
WriteLogToFile(str, LogType.Info);
WriteLogToFile(str);
}
public static void NewLog(Exception ex)
@@ -28,14 +31,40 @@ namespace Ink_Canvas.Helpers
public static void WriteLogToFile(string str, LogType logType = LogType.Info)
{
// 检查日志是否启用
if (MainWindow.Settings != null && MainWindow.Settings.Advanced != null && !MainWindow.Settings.Advanced.IsLogEnabled) return;
string strLogType = logType.ToString();
try
{
var file = App.RootPath + LogFile;
string file;
// 检查是否启用了日期保存功能
if (MainWindow.Settings != null && MainWindow.Settings.Advanced != null && MainWindow.Settings.Advanced.IsSaveLogByDate)
{
// 确保Logs文件夹存在
string logsPath = Path.Combine(App.RootPath, LogsFolder);
if (!Directory.Exists(logsPath))
{
Directory.CreateDirectory(logsPath);
}
// 检查Logs文件夹大小,如果超过5MB则清空
CheckAndCleanLogsFolder(logsPath);
// 使用软件启动时间作为日志文件名
file = Path.Combine(logsPath, $"Log_{AppStartTime}.txt");
}
else
{
file = App.RootPath + LogFile;
}
if (!Directory.Exists(App.RootPath))
{
Directory.CreateDirectory(App.RootPath);
}
var threadId = Thread.CurrentThread.ManagedThreadId;
var callingMethod = new StackTrace(2, true).GetFrame(0);
string callerInfo = "<unknown>";
@@ -57,6 +86,45 @@ namespace Ink_Canvas.Helpers
catch { }
}
private static void CheckAndCleanLogsFolder(string logsPath)
{
try
{
long totalSize = 0;
DirectoryInfo dirInfo = new DirectoryInfo(logsPath);
// 如果目录不存在,直接返回
if (!dirInfo.Exists) return;
// 计算文件夹大小
foreach (FileInfo file in dirInfo.GetFiles())
{
totalSize += file.Length;
}
// 如果超过5MB,清空文件夹
if (totalSize > MaxLogsFolderSizeBytes)
{
foreach (FileInfo file in dirInfo.GetFiles())
{
try
{
file.Delete();
}
catch { }
}
// 记录清理操作
string cleanupMessage = $"Logs folder exceeded size limit ({totalSize / 1024.0 / 1024.0:F2} MB > {MaxLogsFolderSizeBytes / 1024.0 / 1024.0:F2} MB). Folder cleaned.";
using (StreamWriter sw = new StreamWriter(Path.Combine(logsPath, $"Log_{AppStartTime}.txt"), true))
{
sw.WriteLine($"{DateTime.Now:O} [Cleanup] {cleanupMessage}");
}
}
}
catch { }
}
internal static void WriteLogToFile(string v, object warning)
{
WriteLogToFile($"[Warning] {v}", LogType.Warning);
+813
View File
@@ -0,0 +1,813 @@
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Ink;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 多PPT墨迹管理器 - 支持多个PPT窗口分别管理墨迹
/// </summary>
public class MultiPPTInkManager : IDisposable
{
#region Properties
public bool IsAutoSaveEnabled { get; set; } = true;
public string AutoSaveLocation { get; set; } = "";
public PPTManager PPTManager { get; set; }
#endregion
#region Private Fields
private readonly Dictionary<string, PPTInkManager> _presentationManagers;
private readonly Dictionary<string, PresentationInfo> _presentationInfos;
private readonly object _lockObject = new object();
private bool _disposed;
private string _currentActivePresentationId = "";
// 墨迹备份机制
private readonly Dictionary<string, Dictionary<int, StrokeCollection>> _strokeBackups;
private DateTime _lastBackupTime = DateTime.MinValue;
private const int BackupIntervalMinutes = 2; // 每2分钟备份一次
#endregion
#region Constructor
public MultiPPTInkManager()
{
_presentationManagers = new Dictionary<string, PPTInkManager>();
_presentationInfos = new Dictionary<string, PresentationInfo>();
_strokeBackups = new Dictionary<string, Dictionary<int, StrokeCollection>>();
}
#endregion
#region Public Methods
/// <summary>
/// 初始化新的演示文稿
/// </summary>
public void InitializePresentation(Presentation presentation)
{
if (presentation == null) return;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
// 如果已存在该演示文稿的管理器,先清理
if (_presentationManagers.ContainsKey(presentationId))
{
_presentationManagers[presentationId].Dispose();
_presentationManagers.Remove(presentationId);
}
// 创建新的墨迹管理器
var inkManager = new PPTInkManager();
inkManager.IsAutoSaveEnabled = IsAutoSaveEnabled;
inkManager.AutoSaveLocation = AutoSaveLocation;
inkManager.InitializePresentation(presentation);
// 保存管理器和演示文稿信息
_presentationManagers[presentationId] = inkManager;
_presentationInfos[presentationId] = new PresentationInfo
{
Id = presentationId,
Name = presentation.Name,
FullName = presentation.FullName,
SlideCount = presentation.Slides.Count,
CreatedTime = DateTime.Now,
LastAccessTime = DateTime.Now
};
// 设置为当前活跃的演示文稿
_currentActivePresentationId = presentationId;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化多PPT墨迹管理失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 切换到指定的演示文稿
/// </summary>
public bool SwitchToPresentation(Presentation presentation)
{
if (presentation == null) return false;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
if (_presentationManagers.ContainsKey(presentationId))
{
// 如果切换的是不同的演示文稿,先保存当前活跃演示文稿的墨迹
if (!string.IsNullOrEmpty(_currentActivePresentationId) &&
_currentActivePresentationId != presentationId)
{
var currentManager = GetCurrentManager();
if (currentManager != null)
{
// 获取当前活跃的演示文稿并保存墨迹
var currentPresentation = GetCurrentActivePresentation();
if (currentPresentation != null)
{
try
{
currentManager.SaveAllStrokesToFile(currentPresentation);
LogHelper.WriteLogToFile($"已保存当前演示文稿墨迹: {currentPresentation.Name}", LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存当前演示文稿墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
}
_currentActivePresentationId = presentationId;
// 更新最后访问时间
if (_presentationInfos.ContainsKey(presentationId))
{
_presentationInfos[presentationId].LastAccessTime = DateTime.Now;
}
if (_currentActivePresentationId != presentationId)
{
LogHelper.WriteLogToFile($"已切换到演示文稿: {presentation.Name}", LogHelper.LogType.Trace);
}
return true;
}
else
{
// 如果不存在,尝试初始化
InitializePresentation(presentation);
return true;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换到演示文稿失败: {ex}", LogHelper.LogType.Error);
return false;
}
}
}
/// <summary>
/// 保存当前页面的墨迹
/// </summary>
public void SaveCurrentSlideStrokes(int slideIndex, StrokeCollection strokes)
{
if (slideIndex <= 0 || strokes == null) return;
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
// 保存到管理器
manager.SaveCurrentSlideStrokes(slideIndex, strokes);
// 只有在保存成功后才创建备份
if (!string.IsNullOrEmpty(_currentActivePresentationId))
{
CreateStrokeBackup(_currentActivePresentationId, slideIndex, strokes);
}
// 检查是否需要执行定期备份
CheckAndPerformBackup();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存当前页面墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 强制保存指定页面的墨迹(忽略锁定状态)
/// </summary>
public void ForceSaveSlideStrokes(int slideIndex, StrokeCollection strokes)
{
if (slideIndex <= 0 || strokes == null) return;
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
manager.ForceSaveSlideStrokes(slideIndex, strokes);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"强制保存页面墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 加载指定页面的墨迹
/// </summary>
public StrokeCollection LoadSlideStrokes(int slideIndex)
{
if (slideIndex <= 0) return new StrokeCollection();
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
var strokes = manager.LoadSlideStrokes(slideIndex);
// 如果从管理器加载失败,尝试从备份恢复
if (strokes == null || strokes.Count == 0)
{
if (!string.IsNullOrEmpty(_currentActivePresentationId))
{
strokes = RestoreStrokeFromBackup(_currentActivePresentationId, slideIndex);
}
}
return strokes ?? new StrokeCollection();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载页面墨迹失败: {ex}", LogHelper.LogType.Error);
// 尝试从备份恢复
if (!string.IsNullOrEmpty(_currentActivePresentationId))
{
return RestoreStrokeFromBackup(_currentActivePresentationId, slideIndex);
}
}
}
return new StrokeCollection();
}
/// <summary>
/// 切换到指定页面并加载墨迹
/// </summary>
public StrokeCollection SwitchToSlide(int slideIndex, StrokeCollection currentStrokes = null)
{
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
return manager.SwitchToSlide(slideIndex, currentStrokes);
}
else
{
LogHelper.WriteLogToFile($"无法获取当前墨迹管理器,页面切换失败: {slideIndex}", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换页面墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
return new StrokeCollection();
}
/// <summary>
/// 保存所有墨迹到文件
/// </summary>
public void SaveAllStrokesToFile(Presentation presentation)
{
if (!IsAutoSaveEnabled || string.IsNullOrEmpty(AutoSaveLocation) || presentation == null) return;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
if (_presentationManagers.ContainsKey(presentationId))
{
_presentationManagers[presentationId].SaveAllStrokesToFile(presentation);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存所有墨迹到文件失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 从文件加载已保存的墨迹
/// </summary>
public void LoadSavedStrokes(Presentation presentation)
{
if (!IsAutoSaveEnabled || string.IsNullOrEmpty(AutoSaveLocation) || presentation == null) return;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
if (_presentationManagers.ContainsKey(presentationId))
{
_presentationManagers[presentationId].LoadSavedStrokes();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从文件加载墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 清除指定演示文稿的所有墨迹
/// </summary>
public void ClearPresentationStrokes(Presentation presentation)
{
if (presentation == null) return;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
if (_presentationManagers.ContainsKey(presentationId))
{
_presentationManagers[presentationId].ClearAllStrokes();
LogHelper.WriteLogToFile($"已清除演示文稿墨迹: {presentation.Name}", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除演示文稿墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 清除所有演示文稿的墨迹
/// </summary>
public void ClearAllStrokes()
{
lock (_lockObject)
{
try
{
foreach (var manager in _presentationManagers.Values)
{
manager?.ClearAllStrokes();
}
LogHelper.WriteLogToFile("已清除所有演示文稿墨迹", LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除所有墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 翻页后锁定墨迹写入
/// </summary>
public void LockInkForSlide(int slideIndex)
{
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
manager.LockInkForSlide(slideIndex);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"锁定墨迹写入失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 检查是否可以写入墨迹
/// </summary>
public bool CanWriteInk(int currentSlideIndex)
{
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
return manager.CanWriteInk(currentSlideIndex);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"检查墨迹写入权限失败: {ex}", LogHelper.LogType.Error);
}
}
return false;
}
/// <summary>
/// 重置当前演示文稿的墨迹锁定状态
/// </summary>
public void ResetCurrentPresentationLockState()
{
lock (_lockObject)
{
try
{
var manager = GetCurrentManager();
if (manager != null)
{
manager.ResetLockState();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"重置墨迹锁定状态失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 移除演示文稿管理器
/// </summary>
public void RemovePresentation(Presentation presentation)
{
if (presentation == null) return;
lock (_lockObject)
{
try
{
var presentationId = GeneratePresentationId(presentation);
if (_presentationManagers.ContainsKey(presentationId))
{
// 保存墨迹到文件
_presentationManagers[presentationId].SaveAllStrokesToFile(presentation);
// 释放资源
_presentationManagers[presentationId].Dispose();
_presentationManagers.Remove(presentationId);
}
if (_presentationInfos.ContainsKey(presentationId))
{
_presentationInfos.Remove(presentationId);
}
// 如果移除的是当前活跃的演示文稿,重置活跃ID
if (_currentActivePresentationId == presentationId)
{
_currentActivePresentationId = "";
}
}
catch (COMException comEx)
{
var hr = (uint)comEx.HResult;
if (hr == 0x8001010E || hr == 0x80004005 || hr == 0x800706BA || hr == 0x800706BE || hr == 0x80048010)
{
}
}
catch (Exception)
{
}
}
}
/// <summary>
/// 获取当前管理的演示文稿数量
/// </summary>
public int GetPresentationCount()
{
lock (_lockObject)
{
return _presentationManagers.Count;
}
}
/// <summary>
/// 获取所有演示文稿信息
/// </summary>
public List<PresentationInfo> GetAllPresentationInfos()
{
lock (_lockObject)
{
return _presentationInfos.Values.ToList();
}
}
/// <summary>
/// 清理长时间未访问的演示文稿管理器
/// </summary>
public void CleanupInactivePresentations(TimeSpan inactiveThreshold)
{
lock (_lockObject)
{
try
{
var inactiveIds = new List<string>();
var cutoffTime = DateTime.Now - inactiveThreshold;
foreach (var info in _presentationInfos.Values)
{
if (info.LastAccessTime < cutoffTime && info.Id != _currentActivePresentationId)
{
inactiveIds.Add(info.Id);
}
}
foreach (var id in inactiveIds)
{
if (_presentationManagers.ContainsKey(id))
{
_presentationManagers[id].Dispose();
_presentationManagers.Remove(id);
}
_presentationInfos.Remove(id);
// 清理备份数据
if (_strokeBackups.ContainsKey(id))
{
_strokeBackups.Remove(id);
}
LogHelper.WriteLogToFile($"已清理非活跃演示文稿: {id}", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理非活跃演示文稿失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 创建墨迹备份
/// </summary>
private void CreateStrokeBackup(string presentationId, int slideIndex, StrokeCollection strokes)
{
try
{
if (strokes == null || strokes.Count == 0) return;
if (!_strokeBackups.ContainsKey(presentationId))
{
_strokeBackups[presentationId] = new Dictionary<int, StrokeCollection>();
}
// 释放旧的备份
if (_strokeBackups[presentationId].ContainsKey(slideIndex))
{
_strokeBackups[presentationId][slideIndex] = null;
}
// 创建新的备份
_strokeBackups[presentationId][slideIndex] = strokes.Clone();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"创建墨迹备份失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从备份恢复墨迹
/// </summary>
private StrokeCollection RestoreStrokeFromBackup(string presentationId, int slideIndex)
{
try
{
if (_strokeBackups.ContainsKey(presentationId) &&
_strokeBackups[presentationId].ContainsKey(slideIndex))
{
var backup = _strokeBackups[presentationId][slideIndex];
if (backup != null)
{
LogHelper.WriteLogToFile($"从备份恢复第{slideIndex}页墨迹", LogHelper.LogType.Trace);
return backup.Clone();
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从备份恢复墨迹失败: {ex}", LogHelper.LogType.Error);
}
return new StrokeCollection();
}
/// <summary>
/// 检查并执行定期备份
/// </summary>
private void CheckAndPerformBackup()
{
try
{
var now = DateTime.Now;
// 检查是否需要执行备份
if (now - _lastBackupTime < TimeSpan.FromMinutes(BackupIntervalMinutes))
{
return;
}
// 备份当前活跃演示文稿的所有墨迹
if (!string.IsNullOrEmpty(_currentActivePresentationId) &&
_presentationManagers.ContainsKey(_currentActivePresentationId))
{
var manager = _presentationManagers[_currentActivePresentationId];
if (manager != null)
{
// 这里可以添加更详细的备份逻辑
}
}
_lastBackupTime = now;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"定期备份检查失败: {ex}", LogHelper.LogType.Error);
}
}
#endregion
#region Private Methods
private PPTInkManager GetCurrentManager()
{
if (string.IsNullOrEmpty(_currentActivePresentationId) ||
!_presentationManagers.ContainsKey(_currentActivePresentationId))
{
return null;
}
return _presentationManagers[_currentActivePresentationId];
}
private Presentation GetCurrentActivePresentation()
{
try
{
// 通过PPTManager获取当前活跃的演示文稿
return PPTManager?.GetCurrentActivePresentation();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取当前活跃演示文稿失败: {ex}", LogHelper.LogType.Error);
return null;
}
}
private string GeneratePresentationId(Presentation presentation)
{
try
{
// 检查COM对象是否仍然有效
if (presentation == null)
{
return $"invalid_{DateTime.Now.Ticks}";
}
var presentationPath = presentation.FullName;
var fileHash = GetFileHash(presentationPath);
var processId = GetProcessId(presentation);
return $"{presentation.Name}_{presentation.Slides.Count}_{fileHash}_{processId}";
}
catch (COMException comEx)
{
var hr = (uint)comEx.HResult;
if (hr == 0x8001010E || hr == 0x80004005 || hr == 0x800706BA || hr == 0x800706BE || hr == 0x80048010)
{
return $"disconnected_{DateTime.Now.Ticks}";
}
return $"error_{DateTime.Now.Ticks}";
}
catch (Exception)
{
return $"unknown_{DateTime.Now.Ticks}";
}
}
private string GetFileHash(string filePath)
{
try
{
if (string.IsNullOrEmpty(filePath)) return "unknown";
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(filePath));
return BitConverter.ToString(hashBytes).Replace("-", "").Substring(0, 8);
}
}
catch (Exception)
{
// 所有异常都静默处理,避免日志噪音
return "error";
}
}
private string GetProcessId(Presentation presentation)
{
try
{
// 尝试获取PowerPoint应用程序的进程ID
if (presentation.Application != null)
{
// 通过COM对象获取进程信息
var hwnd = presentation.Application.HWND;
if (hwnd != 0)
{
return hwnd.ToString();
}
}
return "unknown";
}
catch (COMException comEx)
{
// COM对象已失效,这是正常情况,完全静默处理
var hr = (uint)comEx.HResult;
if (hr == 0x8001010E || hr == 0x80004005 || hr == 0x800706BA || hr == 0x800706BE || hr == 0x80048010)
{
return "disconnected";
}
return "error";
}
catch (Exception)
{
return "error";
}
}
#endregion
#region Dispose
public void Dispose()
{
if (!_disposed)
{
lock (_lockObject)
{
// 释放所有管理器
foreach (var manager in _presentationManagers.Values)
{
manager?.Dispose();
}
_presentationManagers.Clear();
_presentationInfos.Clear();
// 清理备份数据
foreach (var backupDict in _strokeBackups.Values)
{
foreach (var backup in backupDict.Values)
{
backup?.Clear();
}
backupDict.Clear();
}
_strokeBackups.Clear();
}
_disposed = true;
}
}
#endregion
}
/// <summary>
/// 演示文稿信息
/// </summary>
public class PresentationInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public int SlideCount { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime LastAccessTime { get; set; }
}
}
+36 -5
View File
@@ -25,14 +25,18 @@ namespace Ink_Canvas.Helpers
}
/// <summary>
/// 用于显示笔迹的类
/// 用于显示笔迹的类
/// </summary>
public class StrokeVisual : DrawingVisual
{
private bool _needsRedraw = true;
private int _lastPointCount = 0;
private const int REDRAW_THRESHOLD = 3;
/// <summary>
/// 创建显示笔迹的类
/// </summary>
public StrokeVisual() : this(new DrawingAttributes()
public StrokeVisual() : this(new DrawingAttributes
{
Color = Colors.Red,
//FitToCurve = true,
@@ -49,15 +53,20 @@ namespace Ink_Canvas.Helpers
public StrokeVisual(DrawingAttributes drawingAttributes)
{
_drawingAttributes = drawingAttributes;
// 启用硬件加速
RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.HighQuality);
RenderOptions.SetEdgeMode(this, EdgeMode.Aliased);
RenderOptions.SetCachingHint(this, CachingHint.Cache);
}
/// <summary>
/// 设置或获取显示的笔迹
/// 设置或获取显示的笔迹
/// </summary>
public Stroke Stroke { set; get; }
/// <summary>
/// 在笔迹中添加点
/// 在笔迹中添加点
/// </summary>
/// <param name="point"></param>
public void Add(StylusPoint point)
@@ -66,28 +75,50 @@ namespace Ink_Canvas.Helpers
{
var collection = new StylusPointCollection { point };
Stroke = new Stroke(collection) { DrawingAttributes = _drawingAttributes };
_lastPointCount = 1;
}
else
{
Stroke.StylusPoints.Add(point);
_lastPointCount++;
}
// 标记需要重绘
_needsRedraw = true;
}
/// <summary>
/// 重新画出笔迹
/// 重新画出笔迹
/// </summary>
public void Redraw()
{
if (!_needsRedraw || Stroke == null) return;
if (_lastPointCount % REDRAW_THRESHOLD != 0 && _lastPointCount > REDRAW_THRESHOLD)
{
return;
}
try
{
using (var dc = RenderOpen())
{
Stroke.Draw(dc);
}
_needsRedraw = false;
}
catch { }
}
/// <summary>
/// 强制重绘
/// </summary>
public void ForceRedraw()
{
_needsRedraw = true;
Redraw();
}
private readonly DrawingAttributes _drawingAttributes;
public static implicit operator Stroke(StrokeVisual v)
+659
View File
@@ -0,0 +1,659 @@
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Ink;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// PPT墨迹管理器 - 负责PPT中墨迹的保存、加载和同步
/// </summary>
public class PPTInkManager : IDisposable
{
#region Properties
public bool IsAutoSaveEnabled { get; set; } = true;
public string AutoSaveLocation { get; set; } = "";
public StrokeCollection CurrentStrokes { get; private set; } = new StrokeCollection();
#endregion
#region Private Fields
private MemoryStream[] _memoryStreams;
private int _maxSlides = 100;
private string _currentPresentationId = "";
private readonly object _lockObject = new object();
private bool _disposed;
// 墨迹锁定机制,防止翻页时的墨迹冲突
private DateTime _inkLockUntil = DateTime.MinValue;
private int _lockedSlideIndex = -1;
private const int InkLockMilliseconds = 500;
// 添加快速切换保护机制
private DateTime _lastSwitchTime = DateTime.MinValue;
private int _lastSwitchSlideIndex = -1;
private const int MinSwitchIntervalMs = 100; // 最小切换间隔100毫秒
// 内存管理相关字段
private long _totalMemoryUsage = 0;
private const long MaxMemoryUsageBytes = 100 * 1024 * 1024; // 100MB限制
private DateTime _lastMemoryCleanup = DateTime.MinValue;
private const int MemoryCleanupIntervalMinutes = 5; // 5分钟清理一次
#endregion
#region Constructor
public PPTInkManager()
{
InitializeMemoryStreams();
}
private void InitializeMemoryStreams()
{
_memoryStreams = new MemoryStream[_maxSlides + 2];
}
#endregion
#region Public Methods
/// <summary>
/// 初始化新的演示文稿
/// </summary>
public void InitializePresentation(Presentation presentation)
{
if (presentation == null) return;
lock (_lockObject)
{
try
{
// 完全清理之前的墨迹状态
ClearAllStrokes();
// 重置墨迹锁定状态
_inkLockUntil = DateTime.MinValue;
_lockedSlideIndex = -1;
// 生成演示文稿唯一标识符
_currentPresentationId = GeneratePresentationId(presentation);
// 重新初始化内存流数组
int slideCount = 0;
try
{
slideCount = presentation.Slides.Count;
}
catch (COMException comEx)
{
var hr = (uint)comEx.HResult;
if (hr == 0x80048010)
{
return;
}
throw;
}
_memoryStreams = new MemoryStream[slideCount + 2];
// 如果启用自动保存,尝试加载已保存的墨迹
if (IsAutoSaveEnabled && !string.IsNullOrEmpty(AutoSaveLocation))
{
LoadSavedStrokes();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化演示文稿墨迹管理失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 保存当前页面的墨迹
/// </summary>
public void SaveCurrentSlideStrokes(int slideIndex, StrokeCollection strokes)
{
if (slideIndex <= 0 || strokes == null) return;
lock (_lockObject)
{
try
{
// 检查墨迹锁定
if (!CanWriteInk(slideIndex))
{
if (DateTime.Now < _inkLockUntil)
{
}
return;
}
if (slideIndex < _memoryStreams.Length)
{
// 先释放旧的内存流,防止内存泄漏
try
{
_memoryStreams[slideIndex]?.Dispose();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放旧内存流失败: {ex}", LogHelper.LogType.Warning);
}
// 创建新的内存流
var ms = new MemoryStream();
strokes.Save(ms);
ms.Position = 0;
_memoryStreams[slideIndex] = ms;
if (ms.Length > 0)
{
}
// 检查内存使用情况
CheckAndPerformMemoryCleanup();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存第{slideIndex}页墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 强制保存指定页面的墨迹(忽略锁定状态)
/// </summary>
public void ForceSaveSlideStrokes(int slideIndex, StrokeCollection strokes)
{
if (slideIndex <= 0 || strokes == null) return;
lock (_lockObject)
{
try
{
if (slideIndex < _memoryStreams.Length)
{
// 先释放旧的内存流,防止内存泄漏
try
{
_memoryStreams[slideIndex]?.Dispose();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放旧内存流失败: {ex}", LogHelper.LogType.Warning);
}
// 创建新的内存流
var ms = new MemoryStream();
strokes.Save(ms);
ms.Position = 0;
_memoryStreams[slideIndex] = ms;
LogHelper.WriteLogToFile($"已强制保存第{slideIndex}页墨迹,大小: {ms.Length} bytes", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"强制保存第{slideIndex}页墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 加载指定页面的墨迹
/// </summary>
public StrokeCollection LoadSlideStrokes(int slideIndex)
{
if (slideIndex <= 0) return new StrokeCollection();
lock (_lockObject)
{
try
{
if (slideIndex < _memoryStreams.Length && _memoryStreams[slideIndex] != null && _memoryStreams[slideIndex].Length > 0)
{
_memoryStreams[slideIndex].Position = 0;
var strokes = new StrokeCollection(_memoryStreams[slideIndex]);
return strokes;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载第{slideIndex}页墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
return new StrokeCollection();
}
/// <summary>
/// 切换到指定页面并加载墨迹
/// </summary>
public StrokeCollection SwitchToSlide(int slideIndex, StrokeCollection currentStrokes = null)
{
lock (_lockObject)
{
try
{
// 检查快速切换保护
var now = DateTime.Now;
if (now - _lastSwitchTime < TimeSpan.FromMilliseconds(MinSwitchIntervalMs) &&
_lastSwitchSlideIndex == slideIndex)
{
LogHelper.WriteLogToFile($"快速切换保护:忽略重复的页面切换请求 {slideIndex}", LogHelper.LogType.Warning);
return LoadSlideStrokes(slideIndex);
}
// 设置墨迹锁定
LockInkForSlide(slideIndex);
// 加载新页面的墨迹
var newStrokes = LoadSlideStrokes(slideIndex);
// 更新切换记录
_lastSwitchTime = now;
_lastSwitchSlideIndex = slideIndex;
if (newStrokes.Count > 0)
{
}
return newStrokes;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换到第{slideIndex}页失败: {ex}", LogHelper.LogType.Error);
return new StrokeCollection();
}
}
}
/// <summary>
/// 保存所有墨迹到文件
/// </summary>
public void SaveAllStrokesToFile(Presentation presentation)
{
if (!IsAutoSaveEnabled || string.IsNullOrEmpty(AutoSaveLocation) || presentation == null) return;
lock (_lockObject)
{
try
{
var folderPath = GetPresentationFolderPath();
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
// 保存位置信息
try
{
File.WriteAllText(Path.Combine(folderPath, "Position"), _lockedSlideIndex.ToString());
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存位置信息失败: {ex}", LogHelper.LogType.Error);
}
// 保存所有页面的墨迹
int savedCount = 0;
int slideCount = 0;
try
{
slideCount = presentation.Slides.Count;
}
catch (COMException comEx)
{
var hr = (uint)comEx.HResult;
if (hr == 0x80048010)
{
return;
}
throw;
}
for (int i = 1; i <= slideCount && i < _memoryStreams.Length; i++)
{
if (_memoryStreams[i] != null)
{
try
{
if (_memoryStreams[i].Length > 8)
{
var srcBuf = new byte[_memoryStreams[i].Length];
_memoryStreams[i].Position = 0;
var byteLength = _memoryStreams[i].Read(srcBuf, 0, srcBuf.Length);
var filePath = Path.Combine(folderPath, i.ToString("0000") + ".icstk");
File.WriteAllBytes(filePath, srcBuf);
savedCount++;
}
else
{
// 删除空的墨迹文件
var filePath = Path.Combine(folderPath, i.ToString("0000") + ".icstk");
if (File.Exists(filePath))
{
File.Delete(filePath);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存第{i}页墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存墨迹到文件失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 从文件加载已保存的墨迹
/// </summary>
public void LoadSavedStrokes()
{
if (!IsAutoSaveEnabled || string.IsNullOrEmpty(AutoSaveLocation)) return;
lock (_lockObject)
{
try
{
var folderPath = GetPresentationFolderPath();
if (!Directory.Exists(folderPath)) return;
var files = new DirectoryInfo(folderPath).GetFiles("*.icstk");
int loadedCount = 0;
foreach (var file in files)
{
try
{
if (int.TryParse(Path.GetFileNameWithoutExtension(file.Name), out int slideIndex))
{
if (slideIndex > 0 && slideIndex < _memoryStreams.Length)
{
var fileBytes = File.ReadAllBytes(file.FullName);
_memoryStreams[slideIndex] = new MemoryStream(fileBytes);
_memoryStreams[slideIndex].Position = 0;
loadedCount++;
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载墨迹文件{file.Name}失败: {ex}", LogHelper.LogType.Error);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从文件加载墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 清除所有墨迹
/// </summary>
public void ClearAllStrokes()
{
lock (_lockObject)
{
try
{
// 安全释放所有内存流
if (_memoryStreams != null)
{
for (int i = 0; i < _memoryStreams.Length; i++)
{
try
{
_memoryStreams[i]?.Dispose();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放内存流{i}失败: {ex}", LogHelper.LogType.Warning);
}
finally
{
_memoryStreams[i] = null;
}
}
// 重新初始化数组
_memoryStreams = new MemoryStream[_maxSlides + 2];
}
CurrentStrokes?.Clear();
LogHelper.WriteLogToFile("已清除所有墨迹", LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 翻页后锁定墨迹写入
/// </summary>
public void LockInkForSlide(int slideIndex)
{
_inkLockUntil = DateTime.Now.AddMilliseconds(InkLockMilliseconds);
_lockedSlideIndex = slideIndex;
}
/// <summary>
/// 检查是否可以写入墨迹
/// </summary>
public bool CanWriteInk(int currentSlideIndex)
{
// 如果锁定时间已过,允许写入
if (DateTime.Now >= _inkLockUntil)
{
return true;
}
// 如果当前页面与锁定页面相同,允许写入(用户在当前页面绘制)
if (currentSlideIndex == _lockedSlideIndex)
{
return true;
}
// 如果当前页面不是锁定页面,但锁定时间很短(小于50ms),允许写入
// 这样可以确保旧页面的墨迹能够及时保存
if (DateTime.Now - (_inkLockUntil.AddMilliseconds(-InkLockMilliseconds)) < TimeSpan.FromMilliseconds(50))
{
return true;
}
// 只有在快速切换且页面不同时才锁定
return false;
}
/// <summary>
/// 重置墨迹锁定状态
/// </summary>
public void ResetLockState()
{
lock (_lockObject)
{
_inkLockUntil = DateTime.MinValue;
_lockedSlideIndex = -1;
_lastSwitchTime = DateTime.MinValue;
_lastSwitchSlideIndex = -1;
}
}
/// <summary>
/// 检查并执行内存清理
/// </summary>
private void CheckAndPerformMemoryCleanup()
{
try
{
var now = DateTime.Now;
// 检查是否需要执行内存清理
if (now - _lastMemoryCleanup < TimeSpan.FromMinutes(MemoryCleanupIntervalMinutes))
{
return;
}
// 计算当前内存使用量
long currentMemoryUsage = 0;
if (_memoryStreams != null)
{
for (int i = 0; i < _memoryStreams.Length; i++)
{
if (_memoryStreams[i] != null)
{
currentMemoryUsage += _memoryStreams[i].Length;
}
}
}
_totalMemoryUsage = currentMemoryUsage;
// 如果内存使用量超过限制,执行清理
if (currentMemoryUsage > MaxMemoryUsageBytes)
{
LogHelper.WriteLogToFile($"内存使用量超限 ({currentMemoryUsage / 1024 / 1024}MB),开始清理", LogHelper.LogType.Warning);
// 清理非当前页面的墨迹
CleanupInactiveSlideStrokes();
_lastMemoryCleanup = now;
LogHelper.WriteLogToFile($"内存清理完成,当前使用量: {_totalMemoryUsage / 1024 / 1024}MB", LogHelper.LogType.Trace);
}
else
{
_lastMemoryCleanup = now;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"内存清理检查失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 清理非活跃页面的墨迹
/// </summary>
private void CleanupInactiveSlideStrokes()
{
try
{
if (_memoryStreams == null) return;
int cleanedCount = 0;
long freedMemory = 0;
for (int i = 0; i < _memoryStreams.Length; i++)
{
// 保留当前锁定页面和最近访问的页面
if (i == _lockedSlideIndex || i == _lastSwitchSlideIndex)
{
continue;
}
if (_memoryStreams[i] != null)
{
long memorySize = _memoryStreams[i].Length;
try
{
_memoryStreams[i].Dispose();
freedMemory += memorySize;
cleanedCount++;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理页面{i}墨迹失败: {ex}", LogHelper.LogType.Warning);
}
finally
{
_memoryStreams[i] = null;
}
}
}
if (cleanedCount > 0)
{
LogHelper.WriteLogToFile($"已清理{cleanedCount}个页面的墨迹,释放内存: {freedMemory / 1024}KB", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理非活跃页面墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
#endregion
#region Private Methods
private string GeneratePresentationId(Presentation presentation)
{
try
{
var presentationPath = presentation.FullName;
var fileHash = GetFileHash(presentationPath);
return $"{presentation.Name}_{presentation.Slides.Count}_{fileHash}";
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"生成演示文稿ID失败: {ex}", LogHelper.LogType.Error);
return $"unknown_{DateTime.Now.Ticks}";
}
}
private string GetFileHash(string filePath)
{
try
{
if (string.IsNullOrEmpty(filePath)) return "unknown";
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(filePath));
return BitConverter.ToString(hashBytes).Replace("-", "").Substring(0, 8);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"计算文件哈希值失败: {ex}", LogHelper.LogType.Error);
return "error";
}
}
private string GetPresentationFolderPath()
{
return Path.Combine(AutoSaveLocation, "Auto Saved - Presentations", _currentPresentationId);
}
#endregion
#region Dispose
public void Dispose()
{
if (!_disposed)
{
lock (_lockObject)
{
ClearAllStrokes();
}
_disposed = true;
}
}
#endregion
}
}
File diff suppressed because it is too large Load Diff
+490
View File
@@ -0,0 +1,490 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// PPT UI管理器 - 统一管理PPT相关的UI更新和样式设置
/// </summary>
public class PPTUIManager
{
#region Properties
public bool ShowPPTButton { get; set; } = true;
public int PPTButtonsDisplayOption { get; set; } = 2222;
public int PPTSButtonsOption { get; set; } = 221;
public int PPTBButtonsOption { get; set; } = 121;
public int PPTLSButtonPosition { get; set; } = 0;
public int PPTRSButtonPosition { get; set; } = 0;
public int PPTLBButtonPosition { get; set; } = 0;
public int PPTRBButtonPosition { get; set; } = 0;
public bool EnablePPTButtonPageClickable { get; set; } = true;
public bool EnablePPTButtonLongPressPageTurn { get; set; } = true;
#endregion
#region Private Fields
private readonly MainWindow _mainWindow;
private readonly Dispatcher _dispatcher;
#endregion
#region Constructor
public PPTUIManager(MainWindow mainWindow)
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
_dispatcher = _mainWindow.Dispatcher;
}
#endregion
#region Public Methods
/// <summary>
/// 更新PPT连接状态UI
/// </summary>
public void UpdateConnectionStatus(bool isConnected)
{
_dispatcher.InvokeAsync(() =>
{
try
{
if (isConnected)
{
_mainWindow.StackPanelPPTControls.Visibility = Visibility.Visible;
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Visible;
}
else
{
_mainWindow.StackPanelPPTControls.Visibility = Visibility.Collapsed;
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Collapsed;
_mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Collapsed;
HideAllNavigationPanels();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新PPT连接状态UI失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 更新幻灯片放映状态UI
/// </summary>
public void UpdateSlideShowStatus(bool isInSlideShow, int currentSlide = 0, int totalSlides = 0)
{
_dispatcher.InvokeAsync(() =>
{
try
{
if (isInSlideShow)
{
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Collapsed;
_mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Visible;
// 只有在页数有效时才更新页码显示
if (currentSlide > 0 && totalSlides > 0)
{
_mainWindow.PPTBtnPageNow.Text = currentSlide.ToString();
_mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}";
}
else
{
// 页数无效时清空页码显示
_mainWindow.PPTBtnPageNow.Text = "?";
_mainWindow.PPTBtnPageTotal.Text = "/ ?";
}
UpdateNavigationPanelsVisibility();
UpdateNavigationButtonStyles();
}
else
{
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Visible;
_mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Collapsed;
HideAllNavigationPanels();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新幻灯片放映状态UI失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 更新当前页码显示
/// </summary>
public void UpdateCurrentSlideNumber(int currentSlide, int totalSlides)
{
_dispatcher.InvokeAsync(() =>
{
try
{
// 只有在页数有效时才更新页码显示
if (currentSlide > 0 && totalSlides > 0)
{
_mainWindow.PPTBtnPageNow.Text = currentSlide.ToString();
_mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}";
}
else
{
// 页数无效时清空页码显示
_mainWindow.PPTBtnPageNow.Text = "?";
_mainWindow.PPTBtnPageTotal.Text = "/ ?";
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新页码显示失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 处理PPT放映状态变化
/// </summary>
public void OnSlideShowStateChanged(bool isInSlideShow)
{
_dispatcher.InvokeAsync(() =>
{
try
{
if (!isInSlideShow)
{
// 如果不在放映模式,隐藏所有导航面板
HideAllNavigationPanels();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理PPT放映状态变化失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 更新导航面板显示状态
/// </summary>
public void UpdateNavigationPanelsVisibility()
{
_dispatcher.InvokeAsync(() =>
{
try
{
// 检查是否应该显示PPT按钮
// 不仅要检查按钮设置,还要确保确实在PPT放映模式下且页数有效
bool isInSlideShow = _mainWindow.PPTManager?.IsInSlideShow == true;
int slidesCount = _mainWindow.PPTManager?.SlidesCount ?? 0;
bool hasValidPageCount = slidesCount > 0;
bool shouldShowButtons = ShowPPTButton &&
_mainWindow.BtnPPTSlideShowEnd.Visibility == Visibility.Visible &&
isInSlideShow &&
hasValidPageCount &&
!MainWindow.Settings.Automation.IsAutoFoldInPPTSlideShow;
if (!shouldShowButtons)
{
HideAllNavigationPanels();
return;
}
// 设置侧边按钮位置
_mainWindow.LeftSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTLSButtonPosition * 2);
_mainWindow.RightSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTRSButtonPosition * 2);
// 设置底部按钮水平位置
_mainWindow.LeftBottomPanelForPPTNavigation.Margin = new Thickness(6 + PPTLBButtonPosition, 0, 0, 6);
_mainWindow.RightBottomPanelForPPTNavigation.Margin = new Thickness(0, 0, 6 + PPTRBButtonPosition, 6);
// 根据显示选项设置面板可见性
var displayOption = PPTButtonsDisplayOption.ToString();
if (displayOption.Length >= 4)
{
var options = displayOption.ToCharArray();
// 左下角面板
if (options[0] == '2')
AnimationsHelper.ShowWithFadeIn(_mainWindow.LeftBottomPanelForPPTNavigation);
else
_mainWindow.LeftBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
// 右下角面板
if (options[1] == '2')
AnimationsHelper.ShowWithFadeIn(_mainWindow.RightBottomPanelForPPTNavigation);
else
_mainWindow.RightBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
// 左侧面板
if (options[2] == '2')
AnimationsHelper.ShowWithFadeIn(_mainWindow.LeftSidePanelForPPTNavigation);
else
_mainWindow.LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
// 右侧面板
if (options[3] == '2')
AnimationsHelper.ShowWithFadeIn(_mainWindow.RightSidePanelForPPTNavigation);
else
_mainWindow.RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新导航面板显示状态失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 更新导航按钮样式
/// </summary>
public void UpdateNavigationButtonStyles()
{
_dispatcher.InvokeAsync(() =>
{
try
{
UpdateSideButtonStyles();
UpdateBottomButtonStyles();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新导航按钮样式失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 隐藏所有导航面板
/// </summary>
public void HideAllNavigationPanels()
{
_dispatcher.InvokeAsync(() =>
{
try
{
_mainWindow.LeftBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
_mainWindow.RightBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
_mainWindow.LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
_mainWindow.RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"隐藏导航面板失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 显示/隐藏侧边栏退出按钮
/// </summary>
public void UpdateSidebarExitButtons(bool show)
{
_dispatcher.InvokeAsync(() =>
{
try
{
var visibility = show ? Visibility.Visible : Visibility.Collapsed;
if (_mainWindow.BtnExitPptFromSidebarLeft != null)
_mainWindow.BtnExitPptFromSidebarLeft.Visibility = visibility;
if (_mainWindow.BtnExitPptFromSidebarRight != null)
_mainWindow.BtnExitPptFromSidebarRight.Visibility = visibility;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新侧边栏退出按钮失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 设置浮动栏透明度
/// </summary>
public void SetFloatingBarOpacity(double opacity)
{
_dispatcher.InvokeAsync(() =>
{
try
{
_mainWindow.ViewboxFloatingBar.Opacity = opacity;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置浮动栏透明度失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 设置主面板边距
/// </summary>
public void SetMainPanelMargin(Thickness margin)
{
_dispatcher.InvokeAsync(() =>
{
try
{
_mainWindow.ViewBoxStackPanelMain.Margin = margin;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置主面板边距失败: {ex}", LogHelper.LogType.Error);
}
});
}
#endregion
#region Private Methods
private void UpdateSideButtonStyles()
{
try
{
var sideOption = PPTSButtonsOption.ToString();
if (sideOption.Length < 3) return;
var options = sideOption.ToCharArray();
// 页码按钮显示
var pageButtonVisibility = options[0] == '2' ? Visibility.Visible : Visibility.Collapsed;
_mainWindow.PPTLSPageButton.Visibility = pageButtonVisibility;
_mainWindow.PPTRSPageButton.Visibility = pageButtonVisibility;
// 透明度设置
var opacity = options[1] == '2' ? 0.5 : 1.0;
_mainWindow.PPTBtnLSBorder.Opacity = opacity;
_mainWindow.PPTBtnRSBorder.Opacity = opacity;
// 颜色主题
bool isDarkTheme = options[2] == '2';
ApplyButtonTheme(_mainWindow.PPTBtnLSBorder, _mainWindow.PPTBtnRSBorder, isDarkTheme, true);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新侧边按钮样式失败: {ex}", LogHelper.LogType.Error);
}
}
private void UpdateBottomButtonStyles()
{
try
{
var bottomOption = PPTBButtonsOption.ToString();
if (bottomOption.Length < 3) return;
var options = bottomOption.ToCharArray();
// 页码按钮显示
var pageButtonVisibility = options[0] == '2' ? Visibility.Visible : Visibility.Collapsed;
_mainWindow.PPTLBPageButton.Visibility = pageButtonVisibility;
_mainWindow.PPTRBPageButton.Visibility = pageButtonVisibility;
// 透明度设置
var opacity = options[1] == '2' ? 0.5 : 1.0;
_mainWindow.PPTBtnLBBorder.Opacity = opacity;
_mainWindow.PPTBtnRBBorder.Opacity = opacity;
// 颜色主题
bool isDarkTheme = options[2] == '2';
ApplyButtonTheme(_mainWindow.PPTBtnLBBorder, _mainWindow.PPTBtnRBBorder, isDarkTheme, false);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新底部按钮样式失败: {ex}", LogHelper.LogType.Error);
}
}
private void ApplyButtonTheme(Border leftBorder, Border rightBorder, bool isDarkTheme, bool isSideButton)
{
try
{
Color backgroundColor, borderColor, foregroundColor, feedbackColor;
if (isDarkTheme)
{
backgroundColor = Color.FromRgb(39, 39, 42);
borderColor = Color.FromRgb(82, 82, 91);
foregroundColor = Colors.White;
feedbackColor = Colors.White;
}
else
{
backgroundColor = Color.FromRgb(244, 244, 245);
borderColor = Color.FromRgb(161, 161, 170);
foregroundColor = Color.FromRgb(39, 39, 42);
feedbackColor = Color.FromRgb(24, 24, 27);
}
// 应用背景和边框颜色
var backgroundBrush = new SolidColorBrush(backgroundColor);
var borderBrush = new SolidColorBrush(borderColor);
leftBorder.Background = backgroundBrush;
leftBorder.BorderBrush = borderBrush;
rightBorder.Background = backgroundBrush;
rightBorder.BorderBrush = borderBrush;
// 应用图标和文字颜色
var foregroundBrush = new SolidColorBrush(foregroundColor);
var feedbackBrush = new SolidColorBrush(feedbackColor);
if (isSideButton)
{
ApplySideButtonColors(foregroundBrush, feedbackBrush);
}
else
{
ApplyBottomButtonColors(foregroundBrush, feedbackBrush);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用按钮主题失败: {ex}", LogHelper.LogType.Error);
}
}
private void ApplySideButtonColors(SolidColorBrush foregroundBrush, SolidColorBrush feedbackBrush)
{
// 图标颜色
_mainWindow.PPTLSPreviousButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTRSPreviousButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTLSNextButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTRSNextButtonGeometry.Brush = foregroundBrush;
// 反馈背景颜色
_mainWindow.PPTLSPreviousButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRSPreviousButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTLSPageButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRSPageButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTLSNextButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRSNextButtonFeedbackBorder.Background = feedbackBrush;
// 文字颜色
TextBlock.SetForeground(_mainWindow.PPTLSPageButton, foregroundBrush);
TextBlock.SetForeground(_mainWindow.PPTRSPageButton, foregroundBrush);
}
private void ApplyBottomButtonColors(SolidColorBrush foregroundBrush, SolidColorBrush feedbackBrush)
{
// 图标颜色
_mainWindow.PPTLBPreviousButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTRBPreviousButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTLBNextButtonGeometry.Brush = foregroundBrush;
_mainWindow.PPTRBNextButtonGeometry.Brush = foregroundBrush;
// 反馈背景颜色
_mainWindow.PPTLBPreviousButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRBPreviousButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTLBPageButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRBPageButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTLBNextButtonFeedbackBorder.Background = feedbackBrush;
_mainWindow.PPTRBNextButtonFeedbackBorder.Background = feedbackBrush;
// 文字颜色
TextBlock.SetForeground(_mainWindow.PPTLBPageButton, foregroundBrush);
TextBlock.SetForeground(_mainWindow.PPTRBPageButton, foregroundBrush);
}
#endregion
}
}
@@ -0,0 +1,274 @@
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
/// <summary>
/// 启动台按钮控件
/// </summary>
public class LauncherButton
{
/// <summary>
/// 父插件
/// </summary>
private readonly SuperLauncherPlugin _plugin;
/// <summary>
/// 实际按钮控件
/// </summary>
private readonly SimpleStackPanel _panel;
/// <summary>
/// 获取按钮UI元素
/// </summary>
public UIElement Element => _panel;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="plugin">父插件</param>
public LauncherButton(SuperLauncherPlugin plugin)
{
try
{
_plugin = plugin;
LogHelper.WriteLogToFile("开始创建启动台按钮");
// 创建SimpleStackPanel
_panel = new SimpleStackPanel
{
Name = "Launcher_Icon",
Orientation = Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Center,
Width = 28,
Margin = new Thickness(0, -2, 0, 0),
Background = Brushes.Transparent
};
LogHelper.WriteLogToFile("创建SimpleStackPanel完成");
// 添加图标
var image = CreateIconImage();
_panel.Children.Add(image);
// 添加文本
TextBlock textBlock = new TextBlock
{
Text = "启动台",
Foreground = Brushes.Black,
FontSize = 8,
Margin = new Thickness(0, 1, 0, 0),
TextAlignment = TextAlignment.Center
};
_panel.Children.Add(textBlock);
// 设置鼠标事件
_panel.MouseDown += Panel_MouseDown;
_panel.MouseUp += Panel_MouseUp;
_panel.MouseLeave += Panel_MouseLeave;
// 右键菜单支持
_panel.ContextMenu = CreateContextMenu();
// 设置工具提示
_panel.ToolTip = "启动台";
LogHelper.WriteLogToFile("启动台按钮创建完成");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"创建启动台按钮时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
/// <summary>
/// 创建右键菜单
/// </summary>
private ContextMenu CreateContextMenu()
{
try
{
// 创建菜单
ContextMenu menu = new ContextMenu();
// 创建位置切换菜单项
MenuItem positionMenuItem = new MenuItem();
positionMenuItem.Header = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left ?
"移至右侧" : "移至左侧";
positionMenuItem.Click += (s, e) =>
{
// 切换位置
_plugin.Config.ButtonPosition = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left ?
LauncherButtonPosition.Right : LauncherButtonPosition.Left;
// 更新按钮位置
_plugin.UpdateButtonPosition();
// 保存配置
_plugin.SaveConfig();
LogHelper.WriteLogToFile($"通过右键菜单切换启动台按钮位置为: {_plugin.Config.ButtonPosition}");
};
menu.Items.Add(positionMenuItem);
// 添加设置菜单项
MenuItem settingsMenuItem = new MenuItem();
settingsMenuItem.Header = "打开设置";
settingsMenuItem.Click += (s, e) =>
{
// 打开插件设置窗口
var mainWindow = Application.Current.MainWindow;
if (mainWindow != null)
{
try
{
// 使用反射调用主窗口的ShowPluginSettings方法
var method = mainWindow.GetType().GetMethod("ShowPluginSettings");
if (method != null)
{
method.Invoke(mainWindow, null);
LogHelper.WriteLogToFile("已打开插件设置窗口");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"打开插件设置窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
};
menu.Items.Add(settingsMenuItem);
return menu;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"创建右键菜单时出错: {ex.Message}", LogHelper.LogType.Error);
return null;
}
}
/// <summary>
/// 获取实际的UI元素
/// </summary>
[Obsolete("使用Element属性代替")]
public UIElement GetUIElement()
{
return _panel;
}
/// <summary>
/// 创建图标图像
/// </summary>
private Image CreateIconImage()
{
try
{
// 创建图像
Image image = new Image
{
Height = 17,
Margin = new Thickness(0, 3, 0, 0)
};
// 设置位图缩放模式
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
// 创建绘图图像
DrawingImage drawingImage = new DrawingImage();
DrawingGroup drawingGroup = new DrawingGroup();
drawingGroup.ClipGeometry = Geometry.Parse("M0,0 V24 H24 V0 H0 Z");
// 使用提供的应用网格图标
GeometryDrawing geometryDrawing = new GeometryDrawing
{
Brush = new SolidColorBrush(Color.FromRgb(0x1B, 0x1B, 0x1B)),
Geometry = Geometry.Parse("F0 M24,24z M0,0z M4.41721,4.29873C4.35178,4.29873,4.29873,4.35178,4.29873,4.41721L4.29873,9.15646C4.29873,9.22189,4.35178,9.27494,4.41721,9.27494L9.15646,9.27494C9.22189,9.27494,9.27494,9.22189,9.27494,9.15646L9.27494,4.41721C9.27494,4.35178,9.22189,4.29873,9.15646,4.29873L4.41721,4.29873z M2.64,4.41721C2.64,3.43569,3.43569,2.64,4.41721,2.64L9.15646,2.64C10.138,2.64,10.9337,3.43569,10.9337,4.41721L10.9337,9.15646C10.9337,10.138,10.138,10.9337,9.15646,10.9337L4.41721,10.9337C3.43569,10.9337,2.64,10.138,2.64,9.15646L2.64,4.41721z M14.8435,4.29873C14.7781,4.29873,14.7251,4.35178,14.7251,4.41721L14.7251,9.15646C14.7251,9.22189,14.7781,9.27494,14.8435,9.27494L19.5828,9.27494C19.6482,9.27494,19.7013,9.22189,19.7013,9.15646L19.7013,4.41721C19.7013,4.35178,19.6482,4.29873,19.5828,4.29873L14.8435,4.29873z M13.0663,4.41721C13.0663,3.43569,13.862,2.64,14.8435,2.64L19.5828,2.64C20.5643,2.64,21.36,3.43569,21.36,4.41721L21.36,9.15646C21.36,10.138,20.5643,10.9337,19.5828,10.9337L14.8435,10.9337C13.862,10.9337,13.0663,10.138,13.0663,9.15646L13.0663,4.41721z M14.8435,14.7251C14.7781,14.7251,14.7251,14.7781,14.7251,14.8435L14.7251,19.5828C14.7251,19.6482,14.7781,19.7013,14.8435,19.7013L19.5828,19.7013C19.6482,19.7013,19.7013,19.6482,19.7013,19.5828L19.7013,14.8435C19.7013,14.7781,19.6482,14.7251,19.5828,14.7251L14.8435,14.7251z M13.0663,14.8435C13.0663,13.862,13.862,13.0663,14.8435,13.0663L19.5828,13.0663C20.5643,13.0663,21.36,13.862,21.36,14.8435L21.36,19.5828C21.36,20.5643,20.5643,21.36,19.5828,21.36L14.8435,21.36C13.862,21.36,13.0663,20.5643,13.0663,19.5828L13.0663,14.8435z M4.41721,14.7251C4.35178,14.7251,4.29873,14.7781,4.29873,14.8435L4.29873,19.5828C4.29873,19.6482,4.35178,19.7013,4.41721,19.7013L9.15646,19.7013C9.22189,19.7013,9.27494,19.6482,9.27494,19.5828L9.27494,14.8435C9.27494,14.7781,9.22189,14.7251,9.15646,14.7251L4.41721,14.7251z M2.64,14.8435C2.64,13.862,3.43569,13.0663,4.41721,13.0663L9.15646,13.0663C10.138,13.0663,10.9337,13.862,10.9337,14.8435L10.9337,19.5828C10.9337,20.5643,10.138,21.36,9.15646,21.36L4.41721,21.36C3.43569,21.36,2.64,20.5643,2.64,19.5828L2.64,14.8435z")
};
drawingGroup.Children.Add(geometryDrawing);
// 设置图像源
drawingImage.Drawing = drawingGroup;
image.Source = drawingImage;
return image;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"创建图标图像时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
// 返回一个空图像
return new Image();
}
}
/// <summary>
/// 鼠标按下事件
/// </summary>
private void Panel_MouseDown(object sender, MouseButtonEventArgs e)
{
try
{
// 提供反馈
_panel.Background = new SolidColorBrush(Color.FromArgb(40, 0, 0, 0));
LogHelper.WriteLogToFile("启动台按钮鼠标按下");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动台按钮鼠标按下事件出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 鼠标抬起事件
/// </summary>
private void Panel_MouseUp(object sender, MouseButtonEventArgs e)
{
try
{
// 只有左键点击才显示启动台窗口
if (e.ChangedButton != MouseButton.Left)
{
return;
}
// 恢复背景
_panel.Background = Brushes.Transparent;
LogHelper.WriteLogToFile("启动台按钮鼠标抬起,准备显示启动台窗口");
// 获取按钮在屏幕上的位置
Point buttonPosition = _panel.PointToScreen(new Point(_panel.ActualWidth / 2, 0));
// 显示启动台窗口
_plugin.ShowLauncherWindow(buttonPosition);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动台按钮鼠标抬起事件出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
/// <summary>
/// 鼠标离开事件
/// </summary>
private void Panel_MouseLeave(object sender, MouseEventArgs e)
{
try
{
// 恢复背景
_panel.Background = Brushes.Transparent;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动台按钮鼠标离开事件出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
}
@@ -0,0 +1,332 @@
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
/// <summary>
/// 启动台按钮位置
/// </summary>
public enum LauncherButtonPosition
{
/// <summary>
/// 左侧
/// </summary>
Left,
/// <summary>
/// 右侧
/// </summary>
Right
}
/// <summary>
/// 启动台配置
/// </summary>
public class LauncherConfig
{
/// <summary>
/// 启动台按钮位置
/// </summary>
public LauncherButtonPosition ButtonPosition { get; set; } = LauncherButtonPosition.Right;
/// <summary>
/// 启动台应用程序列表
/// </summary>
public List<LauncherItem> Items { get; set; } = new List<LauncherItem>();
}
/// <summary>
/// 启动台应用项
/// </summary>
public class LauncherItem
{
/// <summary>
/// 应用程序名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 应用程序路径
/// </summary>
public string Path { get; set; }
/// <summary>
/// 是否可见
/// </summary>
public bool IsVisible { get; set; } = true;
/// <summary>
/// 在启动台中的位置(0-39
/// </summary>
public int Position { get; set; } = -1;
/// <summary>
/// 是否已固定位置
/// </summary>
public bool IsPositionFixed { get; set; } = false;
/// <summary>
/// 图标缓存
/// </summary>
[JsonIgnore]
private ImageSource _iconCache;
/// <summary>
/// 获取应用程序图标
/// </summary>
[JsonIgnore]
public ImageSource Icon
{
get
{
if (_iconCache != null)
{
return _iconCache;
}
try
{
if (File.Exists(Path))
{
// 从文件中获取图标
Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(Path);
if (icon != null)
{
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
icon.Dispose();
return _iconCache;
}
}
else
{
// 从注册表中获取文件类型关联图标
string extension = System.IO.Path.GetExtension(Path);
if (!string.IsNullOrEmpty(extension))
{
string fileType = Registry.ClassesRoot.OpenSubKey(extension)?.GetValue(string.Empty) as string;
if (!string.IsNullOrEmpty(fileType))
{
string iconPath = Registry.ClassesRoot.OpenSubKey(fileType + "\\DefaultIcon")?.GetValue(string.Empty) as string;
if (!string.IsNullOrEmpty(iconPath))
{
string[] parts = iconPath.Split(',');
string iconFile = parts[0].Trim('"');
int iconIndex = parts.Length > 1 ? Convert.ToInt32(parts[1]) : 0;
if (File.Exists(iconFile))
{
Icon icon = IconExtractor.Extract(iconFile, iconIndex, true);
if (icon != null)
{
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
icon.Dispose();
return _iconCache;
}
}
}
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取应用图标时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 返回默认图标
return GetDefaultIcon();
}
}
/// <summary>
/// 获取默认图标
/// </summary>
private ImageSource GetDefaultIcon()
{
try
{
// 对于资源管理器,使用特定图标
if (Path.EndsWith("explorer.exe", StringComparison.OrdinalIgnoreCase))
{
try
{
// 直接从C:\Windows\explorer.exe获取图标
string explorerPath = @"C:\Windows\explorer.exe";
if (File.Exists(explorerPath))
{
Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(explorerPath);
if (icon != null)
{
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
icon.Dispose();
return _iconCache;
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取资源管理器图标时出错: {ex.Message}", LogHelper.LogType.Warning);
// 如果获取Windows图标失败,回退到默认图标
}
// 回退到备用图标
string explorerIconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-Fluent", "ic_fluent_folder_24_regular.png");
if (File.Exists(explorerIconPath))
{
Uri uri = new Uri(explorerIconPath);
BitmapImage image = new BitmapImage(uri);
_iconCache = image;
return _iconCache;
}
}
// 返回一个简单的默认图标
string iconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-png", "icc.png");
if (File.Exists(iconPath))
{
Uri uri = new Uri(iconPath);
BitmapImage image = new BitmapImage(uri);
_iconCache = image;
return _iconCache;
}
// 如果还是没有找到,尝试使用应用程序图标
string appIconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-Fluent", "ic_fluent_apps_24_regular.png");
if (File.Exists(appIconPath))
{
Uri uri = new Uri(appIconPath);
BitmapImage image = new BitmapImage(uri);
_iconCache = image;
return _iconCache;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取默认图标时出错: {ex.Message}", LogHelper.LogType.Error);
}
return null;
}
/// <summary>
/// 启动应用程序
/// </summary>
public void Launch()
{
try
{
if (string.IsNullOrEmpty(Path))
{
LogHelper.WriteLogToFile("无法启动应用程序:路径为空", LogHelper.LogType.Error);
return;
}
// 检查文件是否存在
if (!File.Exists(Path) && !Path.Contains(":\\"))
{
// 可能是系统命令,如explorer.exe
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = Path,
UseShellExecute = true
};
Process.Start(psi);
}
else
{
// 使用Process.Start启动应用程序
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = Path,
UseShellExecute = true
};
Process.Start(psi);
}
LogHelper.WriteLogToFile($"已启动应用程序: {Path}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动应用程序时出错: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show($"启动应用程序时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
/// <summary>
/// 图标提取工具类
/// </summary>
public static class IconExtractor
{
/// <summary>
/// 从文件中提取图标
/// </summary>
/// <param name="file">文件路径</param>
/// <param name="index">图标索引</param>
/// <param name="largeIcon">是否提取大图标</param>
/// <returns>提取的图标</returns>
public static Icon Extract(string file, int index, bool largeIcon)
{
try
{
IntPtr large;
IntPtr small;
ExtractIconEx(file, index, out large, out small, 1);
try
{
return Icon.FromHandle(largeIcon ? large : small);
}
catch
{
return null;
}
finally
{
if (large != IntPtr.Zero)
DestroyIcon(large);
if (small != IntPtr.Zero)
DestroyIcon(small);
}
}
catch
{
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconEx")]
private static extern int ExtractIconEx(
[MarshalAs(UnmanagedType.LPStr)] string lpszFile,
int nIconIndex,
out IntPtr phiconLarge,
out IntPtr phiconSmall,
int nIcons);
[DllImport("User32.dll")]
private static extern int DestroyIcon(IntPtr hIcon);
}
}
@@ -0,0 +1,143 @@
<UserControl x:Class="Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher.LauncherSettingsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="600">
<UserControl.Resources>
<!-- 自定义按钮样式 -->
<Style x:Key="DefaultButtonStyle" TargetType="Button">
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.8"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Black" Direction="270" ShadowDepth="2" Opacity="0.3" BlurRadius="4"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.6"/>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="0.95" ScaleY="0.95"/>
</Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Opacity" Value="0.4"/>
<Setter Property="Cursor" Value="Arrow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 标题 -->
<TextBlock Grid.Row="0" Text="超级启动台设置" FontSize="16" FontWeight="Bold" Margin="0,0,0,15" Foreground="Black"/>
<!-- 基本设置 -->
<StackPanel Grid.Row="1" Margin="0,0,0,15">
<TextBlock Text="基本设置" FontSize="14" FontWeight="SemiBold" Margin="0,0,0,10" Foreground="Black"/>
<Grid Margin="10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 按钮位置 -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="按钮位置:" VerticalAlignment="Center" Foreground="Black"/>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Margin="0,5">
<RadioButton x:Name="RbtnLeft" Content="浮动栏左侧" Margin="0,0,20,0" Checked="RbtnPosition_Checked" Foreground="Black"/>
<RadioButton x:Name="RbtnRight" Content="浮动栏右侧" IsChecked="True" Checked="RbtnPosition_Checked" Foreground="Black"/>
</StackPanel>
</Grid>
</StackPanel>
<!-- 应用管理 -->
<Grid Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="应用管理" FontSize="14" FontWeight="SemiBold" Margin="0,0,0,10" Foreground="Black"/>
<Border Grid.Row="1" BorderThickness="1" BorderBrush="#CCCCCC" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 应用列表 -->
<DataGrid Grid.Row="0" x:Name="DgApps" AutoGenerateColumns="False" Margin="5"
CanUserAddRows="False" CanUserDeleteRows="False"
HeadersVisibility="Column" SelectionMode="Single"
SelectionChanged="DgApps_SelectionChanged">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="显示" Binding="{Binding IsVisible}" Width="50"/>
<DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="150"/>
<DataGridTextColumn Header="路径" Binding="{Binding Path}" Width="*"/>
<DataGridTextColumn Header="位置" Binding="{Binding Position}" Width="50"/>
</DataGrid.Columns>
</DataGrid>
<!-- 操作按钮 -->
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
<Button x:Name="BtnAdd" Content="添加" Padding="10,5" Margin="0,5,5,5" Click="BtnAdd_Click"
Background="#FF007ACC" Foreground="White" BorderBrush="#FF005A9B" BorderThickness="1"
Style="{StaticResource DefaultButtonStyle}"/>
<Button x:Name="BtnEdit" Content="编辑" Padding="10,5" Margin="5" Click="BtnEdit_Click"
Background="#FF6C757D" Foreground="White" BorderBrush="#FF5A6268" BorderThickness="1"
Style="{StaticResource DefaultButtonStyle}"/>
<Button x:Name="BtnDelete" Content="删除" Padding="10,5" Margin="5" Click="BtnDelete_Click"
Background="#FFDC3545" Foreground="White" BorderBrush="#FFBD2130" BorderThickness="1"
Style="{StaticResource DefaultButtonStyle}"/>
</StackPanel>
</Grid>
</Border>
</Grid>
<!-- 底部按钮 -->
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
<Button x:Name="BtnSave" Content="保存设置" Padding="15,5" Click="BtnSave_Click"
Background="#FF28A745" Foreground="White" BorderBrush="#FF1E7E34" BorderThickness="1"
Style="{StaticResource DefaultButtonStyle}"/>
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,396 @@
using Ink_Canvas.Windows;
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
/// <summary>
/// LauncherSettingsControl.xaml 的交互逻辑
/// </summary>
public partial class LauncherSettingsControl : UserControl
{
/// <summary>
/// 父插件
/// </summary>
private readonly SuperLauncherPlugin _plugin;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="plugin">父插件</param>
public LauncherSettingsControl(SuperLauncherPlugin plugin)
{
InitializeComponent();
_plugin = plugin;
// 设置按钮位置
RbtnLeft.IsChecked = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left;
RbtnRight.IsChecked = _plugin.Config.ButtonPosition == LauncherButtonPosition.Right;
// 绑定应用列表
DgApps.ItemsSource = _plugin.LauncherItems;
// 初始化按钮状态
UpdateButtonStates();
}
/// <summary>
/// 更新按钮状态
/// </summary>
private void UpdateButtonStates()
{
bool hasSelection = DgApps.SelectedItem != null;
BtnEdit.IsEnabled = hasSelection;
BtnDelete.IsEnabled = hasSelection;
}
/// <summary>
/// 位置单选按钮选择事件
/// </summary>
private void RbtnPosition_Checked(object sender, RoutedEventArgs e)
{
if (!IsLoaded) return;
LauncherButtonPosition oldPosition = _plugin.Config.ButtonPosition;
if (sender == RbtnLeft)
{
_plugin.Config.ButtonPosition = LauncherButtonPosition.Left;
}
else if (sender == RbtnRight)
{
_plugin.Config.ButtonPosition = LauncherButtonPosition.Right;
}
// 如果位置发生变化,更新按钮位置
if (oldPosition != _plugin.Config.ButtonPosition)
{
try
{
// 更新按钮位置
_plugin.UpdateButtonPosition();
// 保存配置
_plugin.SaveConfig();
LogHelper.WriteLogToFile($"启动台按钮位置已更改为: {_plugin.Config.ButtonPosition}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新启动台按钮位置时出错: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show($"更新启动台按钮位置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
/// <summary>
/// 添加按钮点击事件
/// </summary>
private void BtnAdd_Click(object sender, RoutedEventArgs e)
{
try
{
// 创建新的启动项
LauncherItem item = new LauncherItem
{
Name = "",
Path = "",
IsVisible = true,
Position = -1 // 让插件管理器分配位置
};
// 直接显示编辑对话框
EditLauncherItem(item, true);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加启动项时出错: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show($"添加启动项时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 编辑应用按钮点击事件
/// </summary>
private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
if (DgApps.SelectedItem is LauncherItem item)
{
EditLauncherItem(item, false);
}
}
/// <summary>
/// 删除应用按钮点击事件
/// </summary>
private void BtnDelete_Click(object sender, RoutedEventArgs e)
{
if (DgApps.SelectedItem is LauncherItem item)
{
// 确认删除
MessageBoxResult result = MessageBox.Show(
$"确定要删除 {item.Name} 吗?",
"删除确认",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
// 从集合中移除
_plugin.LauncherItems.Remove(item);
// 保存配置
_plugin.SaveConfig();
}
}
}
/// <summary>
/// 保存设置按钮点击事件
/// </summary>
private void BtnSave_Click(object sender, RoutedEventArgs e)
{
try
{
// 保存配置
_plugin.SaveConfig();
// 如果插件已启用,重新加载启动台按钮
if (_plugin.IsEnabled)
{
_plugin.Disable();
_plugin.Enable();
}
else
{
// 如果插件未启用,则启用它
_plugin.Enable();
// 通知PluginSettingsWindow刷新插件列表
var window = Window.GetWindow(this);
if (window is PluginSettingsWindow pluginSettingsWindow)
{
// 触发刷新
pluginSettingsWindow.RefreshPluginList();
}
}
MessageBox.Show("设置已保存并应用!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存设置时出错: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show($"保存设置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 应用项选择变更事件
/// </summary>
private void DgApps_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateButtonStates();
}
/// <summary>
/// 编辑启动项
/// </summary>
/// <param name="item">启动项</param>
/// <param name="isNew">是否为新建</param>
private void EditLauncherItem(LauncherItem item, bool isNew)
{
// 创建简单的编辑窗口
Window editWindow = new Window
{
Title = isNew ? "添加" : "编辑应用",
Width = 400,
Height = 200,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
ResizeMode = ResizeMode.NoResize
};
// 创建编辑表单
Grid grid = new Grid
{
Margin = new Thickness(20)
};
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
// 名称输入框
TextBlock nameLabel = new TextBlock
{
Text = "名称:",
VerticalAlignment = VerticalAlignment.Center
};
TextBox nameTextBox = new TextBox
{
Text = item.Name,
Margin = new Thickness(0, 5, 0, 5)
};
Grid.SetRow(nameLabel, 0);
Grid.SetColumn(nameLabel, 0);
Grid.SetRow(nameTextBox, 0);
Grid.SetColumn(nameTextBox, 1);
grid.Children.Add(nameLabel);
grid.Children.Add(nameTextBox);
// 路径输入框
TextBlock pathLabel = new TextBlock
{
Text = "路径:",
VerticalAlignment = VerticalAlignment.Center
};
Grid pathGrid = new Grid();
pathGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
pathGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength() });
TextBox pathTextBox = new TextBox
{
Text = item.Path,
Margin = new Thickness(0, 5, 5, 5)
};
Button browseButton = new Button
{
Content = "浏览",
Padding = new Thickness(5, 0, 5, 0),
Margin = new Thickness(0, 5, 0, 5)
};
browseButton.Click += (s, e) =>
{
OpenFileDialog dialog = new OpenFileDialog
{
Title = "选择应用程序",
Filter = "应用程序 (*.exe)|*.exe|所有文件 (*.*)|*.*",
Multiselect = false,
FileName = pathTextBox.Text
};
if (dialog.ShowDialog() == true)
{
pathTextBox.Text = dialog.FileName;
// 如果选择的是.exe文件,自动获取文件名填入名称字段
if (Path.GetExtension(dialog.FileName).ToLower() == ".exe")
{
string fileName = Path.GetFileNameWithoutExtension(dialog.FileName);
// 只有在名称字段为空或者是新建项目时才自动填入
if (string.IsNullOrWhiteSpace(nameTextBox.Text) || isNew)
{
nameTextBox.Text = fileName;
}
}
}
};
Grid.SetColumn(pathTextBox, 0);
Grid.SetColumn(browseButton, 1);
pathGrid.Children.Add(pathTextBox);
pathGrid.Children.Add(browseButton);
Grid.SetRow(pathLabel, 1);
Grid.SetColumn(pathLabel, 0);
Grid.SetRow(pathGrid, 1);
Grid.SetColumn(pathGrid, 1);
grid.Children.Add(pathLabel);
grid.Children.Add(pathGrid);
// 确认和取消按钮
StackPanel buttonPanel = new StackPanel
{
Orientation = Orientation.Horizontal,
HorizontalAlignment = HorizontalAlignment.Right,
Margin = new Thickness(0, 10, 0, 0)
};
Button okButton = new Button
{
Content = "确定",
Padding = new Thickness(15, 5, 15, 5),
Margin = new Thickness(0, 0, 10, 0),
IsDefault = true
};
Button cancelButton = new Button
{
Content = "取消",
Padding = new Thickness(15, 5, 15, 5),
IsCancel = true
};
okButton.Click += (s, e) =>
{
// 验证输入
if (string.IsNullOrWhiteSpace(nameTextBox.Text))
{
MessageBox.Show("请输入应用名称!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (string.IsNullOrWhiteSpace(pathTextBox.Text))
{
MessageBox.Show("请输入应用路径!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 更新项目
item.Name = nameTextBox.Text;
item.Path = pathTextBox.Text;
// 如果是新建,添加到集合
if (isNew)
{
_plugin.AddLauncherItem(item);
}
else
{
// 触发属性变更通知,刷新DataGrid
if (DgApps.ItemsSource is ICollectionView view)
{
view.Refresh();
}
// 保存配置
_plugin.SaveConfig();
}
editWindow.DialogResult = true;
editWindow.Close();
};
cancelButton.Click += (s, e) =>
{
editWindow.DialogResult = false;
editWindow.Close();
};
buttonPanel.Children.Add(okButton);
buttonPanel.Children.Add(cancelButton);
Grid.SetRow(buttonPanel, 2);
Grid.SetColumnSpan(buttonPanel, 2);
grid.Children.Add(buttonPanel);
// 设置窗口内容
editWindow.Content = grid;
// 显示窗口
editWindow.ShowDialog();
}
}
}
@@ -0,0 +1,91 @@
<Window x:Class="Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher.LauncherWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher"
mc:Ignorable="d"
Title="启动台"
Width="400"
Height="300"
WindowStyle="None"
AllowsTransparency="True"
Background="#80000000"
ResizeMode="NoResize"
Topmost="True"
Deactivated="Window_Deactivated"
ShowInTaskbar="False">
<Window.Resources>
<!-- 应用项样式 -->
<Style x:Key="LauncherItemStyle" TargetType="Button">
<Setter Property="Width" Value="80"/>
<Setter Property="Height" Value="80"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Background" Value="#40FFFFFF"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="8">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Icon}" Width="32" Height="32" Margin="0,10,0,5"/>
<TextBlock Grid.Row="1" Text="{Binding Name}" TextWrapping="Wrap" TextAlignment="Center"
Margin="2,0,2,8" FontSize="11" Foreground="White"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#80FFFFFF"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#C0FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Border CornerRadius="15" Background="#80000000" BorderThickness="1" BorderBrush="#40FFFFFF">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 标题栏 -->
<Grid Grid.Row="0" Height="40">
<TextBlock Text="启动台" Foreground="White" FontSize="18" FontWeight="Bold"
VerticalAlignment="Center" Margin="15,0,0,0"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,0">
<Button x:Name="BtnFixMode" Click="BtnFixMode_Click" Width="30" Height="30"
Margin="5,0" Background="Transparent" BorderThickness="0"
ToolTip="切换固定模式">
<Path x:Name="FixModeIcon" Data="M7,2V13H10V22L17,10H13L17,2H7Z" Fill="White" Stretch="Uniform" Width="16" Height="16"/>
</Button>
<Button x:Name="BtnClose" Click="BtnClose_Click" Width="30" Height="30"
Background="Transparent" BorderThickness="0"
ToolTip="关闭">
<Path Data="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
Fill="White" Stretch="Uniform" Width="16" Height="16"/>
</Button>
</StackPanel>
</Grid>
<!-- 应用网格 -->
<ScrollViewer Grid.Row="1" Margin="10" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<WrapPanel x:Name="AppPanel" Orientation="Horizontal" HorizontalAlignment="Center"/>
</ScrollViewer>
</Grid>
</Border>
</Window>
@@ -0,0 +1,466 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
/// <summary>
/// LauncherWindow.xaml 的交互逻辑
/// </summary>
public partial class LauncherWindow : Window
{
/// <summary>
/// 父插件
/// </summary>
private readonly SuperLauncherPlugin _plugin;
/// <summary>
/// 是否处于固定模式
/// </summary>
private bool _isFixMode;
/// <summary>
/// 应用项按钮列表
/// </summary>
private readonly Dictionary<Button, LauncherItem> _appButtons = new Dictionary<Button, LauncherItem>();
/// <summary>
/// 拖拽中的按钮
/// </summary>
private Button _draggingButton;
/// <summary>
/// 拖拽开始位置
/// </summary>
private Point _dragStartPoint;
/// <summary>
/// 构造函数
/// </summary>
public LauncherWindow(SuperLauncherPlugin plugin)
{
InitializeComponent();
_plugin = plugin;
// 加载应用项
LoadLauncherItems();
// 添加鼠标按下事件(用于拖动窗口)
MouseDown += (s, e) =>
{
if (e.ChangedButton == MouseButton.Left && e.ButtonState == MouseButtonState.Pressed)
{
DragMove();
}
};
// 根据应用数量调整窗口大小
AdjustWindowSize();
}
/// <summary>
/// 加载启动台应用项
/// </summary>
private void LoadLauncherItems()
{
// 清空现有应用项
AppPanel.Children.Clear();
_appButtons.Clear();
// 获取显示的应用项
var visibleItems = _plugin.LauncherItems
.Where(item => item.IsVisible)
.OrderBy(item => item.Position)
.ToList();
foreach (var item in visibleItems)
{
// 创建应用按钮
Button appButton = new Button
{
Style = (Style)FindResource("LauncherItemStyle"),
DataContext = item,
Tag = item.Position
};
// 添加点击事件
appButton.Click += AppButton_Click;
// 在固定模式下,添加拖拽事件
appButton.PreviewMouseDown += AppButton_PreviewMouseDown;
appButton.PreviewMouseMove += AppButton_PreviewMouseMove;
appButton.PreviewMouseUp += AppButton_PreviewMouseUp;
// 记录按钮和项目的对应关系
_appButtons.Add(appButton, item);
// 添加到面板
AppPanel.Children.Add(appButton);
}
}
/// <summary>
/// 根据应用数量调整窗口大小
/// </summary>
private void AdjustWindowSize()
{
try
{
// 每行最多显示4个应用
const int appsPerRow = 4;
// 计算行数
int visibleCount = _appButtons.Count;
int rowCount = (int)Math.Ceiling(visibleCount / (double)appsPerRow);
// 设置窗口宽度(每个应用90像素宽 = 80 + 5*2
Width = Math.Min(appsPerRow * 90 + 40, 400); // 最大宽度400
// 设置窗口高度(每个应用90像素高 = 80 + 5*2
Height = Math.Min(rowCount * 90 + 60, 600); // 最大高度600,标题栏40 + 边距20
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"调整启动台窗口大小时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 应用按钮点击事件
/// </summary>
private void AppButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_isFixMode) return; // 在固定模式下,不响应点击事件
if (sender is Button button && _appButtons.TryGetValue(button, out LauncherItem item))
{
// 获取应用路径和名称,用于后续启动
string appPath = item.Path;
string appName = item.Name;
LogHelper.WriteLogToFile($"点击启动应用: {appName}, 路径: {appPath}");
// 首先标记窗口正在关闭
IsClosing = true;
// 创建一个应用启动任务
var launchTask = new Task(() =>
{
try
{
// 等待一段时间,确保窗口关闭流程已经开始
Thread.Sleep(200);
// 使用UI线程启动应用
Application.Current.Dispatcher.Invoke(() =>
{
try
{
// 检查应用路径是否存在
if (File.Exists(appPath) || !appPath.Contains(":\\"))
{
// 创建进程启动信息
var psi = new ProcessStartInfo
{
FileName = appPath,
UseShellExecute = true,
};
// 启动应用程序
var process = Process.Start(psi);
LogHelper.WriteLogToFile($"应用程序 {appName} 已启动");
}
else
{
LogHelper.WriteLogToFile($"应用路径不存在: {appPath}", LogHelper.LogType.Error);
MessageBox.Show($"找不到应用程序: {appPath}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动应用程序失败: {ex.Message}", LogHelper.LogType.Error);
MessageBox.Show($"启动应用程序失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用启动任务出错: {ex.Message}", LogHelper.LogType.Error);
}
});
// 关闭窗口
try
{
Dispatcher.BeginInvoke(new Action(() =>
{
try { Close(); } catch { }
// 启动应用程序任务
launchTask.Start();
}), DispatcherPriority.Background);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"关闭窗口或启动任务时出错: {ex.Message}", LogHelper.LogType.Error);
// 如果无法通过UI关闭窗口,直接启动任务
launchTask.Start();
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用按钮点击事件出错: {ex.Message}", LogHelper.LogType.Error);
try { IsClosing = true; Close(); } catch { }
}
}
#region
/// <summary>
/// 应用按钮鼠标按下事件
/// </summary>
private void AppButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (!_isFixMode) return;
if (e.ChangedButton == MouseButton.Left && sender is Button button)
{
_draggingButton = button;
_dragStartPoint = e.GetPosition(AppPanel);
button.CaptureMouse();
button.Opacity = 0.7;
// 阻止事件冒泡,以避免触发按钮点击
e.Handled = true;
}
}
/// <summary>
/// 应用按钮鼠标移动事件
/// </summary>
private void AppButton_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (!_isFixMode || _draggingButton == null) return;
if (e.LeftButton == MouseButtonState.Pressed)
{
Point currentPosition = e.GetPosition(AppPanel);
// 移动按钮
System.Windows.Controls.Canvas.SetLeft(_draggingButton, currentPosition.X - _draggingButton.ActualWidth / 2);
System.Windows.Controls.Canvas.SetTop(_draggingButton, currentPosition.Y - _draggingButton.ActualHeight / 2);
// 将按钮移到最上层
Panel.SetZIndex(_draggingButton, 100);
// 阻止事件冒泡
e.Handled = true;
}
}
/// <summary>
/// 应用按钮鼠标释放事件
/// </summary>
private void AppButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (!_isFixMode || _draggingButton == null) return;
// 释放鼠标捕获
_draggingButton.ReleaseMouseCapture();
// 计算新位置
Point releasePoint = e.GetPosition(AppPanel);
int newPosition = CalculateGridPosition(releasePoint);
// 获取当前项目
LauncherItem currentItem = _appButtons[_draggingButton];
// 重新排序
ReorderItems(currentItem, newPosition);
// 重新加载应用项
LoadLauncherItems();
// 保存配置
_plugin.SaveConfig();
// 清除拖拽状态
_draggingButton.Opacity = 1;
Panel.SetZIndex(_draggingButton, 0);
_draggingButton = null;
// 阻止事件冒泡
e.Handled = true;
}
/// <summary>
/// 计算网格位置
/// </summary>
private int CalculateGridPosition(Point point)
{
// 计算行和列
int columnCount = 4; // 每行最多4个应用
int columnWidth = 90; // 应用宽度(包括边距)
int rowHeight = 90; // 应用高度(包括边距)
int column = (int)(point.X / columnWidth);
int row = (int)(point.Y / rowHeight);
// 确保在有效范围内
column = Math.Max(0, Math.Min(column, columnCount - 1));
row = Math.Max(0, row);
// 计算位置索引
return row * columnCount + column;
}
/// <summary>
/// 重新排序应用项
/// </summary>
private void ReorderItems(LauncherItem item, int newPosition)
{
try
{
// 设置项目为固定位置
item.IsPositionFixed = true;
// 如果位置相同,无需调整
if (item.Position == newPosition)
{
return;
}
// 获取所有可见项目
var visibleItems = _plugin.LauncherItems
.Where(i => i.IsVisible)
.OrderBy(i => i.Position)
.ToList();
// 移除当前项目
visibleItems.Remove(item);
// 查找插入位置
int insertIndex = 0;
for (int i = 0; i < visibleItems.Count; i++)
{
if (visibleItems[i].Position >= newPosition)
{
insertIndex = i;
break;
}
insertIndex = i + 1;
}
// 插入项目
visibleItems.Insert(insertIndex, item);
// 重新分配位置
for (int i = 0; i < visibleItems.Count; i++)
{
visibleItems[i].Position = i;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"重新排序应用项时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
/// <summary>
/// 窗口失去焦点事件
/// </summary>
private void Window_Deactivated(object sender, EventArgs e)
{
try
{
// 只有在非固定模式、窗口已加载、未处于关闭状态且IsLoaded=true时关闭窗口
if (!_isFixMode && IsLoaded && !IsClosing)
{
// 标记为正在关闭
IsClosing = true;
// 使用Dispatcher.BeginInvoke而不是直接调用Close,避免冲突
Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 再次检查窗口状态
if (IsLoaded && !IsClosing)
{
Close();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"延迟关闭窗口时出错: {ex.Message}", LogHelper.LogType.Error);
}
}), DispatcherPriority.Background);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"窗口失去焦点关闭时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 窗口是否正在关闭
/// </summary>
private bool IsClosing { get; set; }
/// <summary>
/// 重写OnClosing方法,标记窗口正在关闭
/// </summary>
protected override void OnClosing(CancelEventArgs e)
{
IsClosing = true;
base.OnClosing(e);
}
/// <summary>
/// 关闭按钮点击事件
/// </summary>
private void BtnClose_Click(object sender, RoutedEventArgs e)
{
Close();
}
/// <summary>
/// 固定模式按钮点击事件
/// </summary>
private void BtnFixMode_Click(object sender, RoutedEventArgs e)
{
// 切换固定模式
_isFixMode = !_isFixMode;
// 更新固定模式按钮图标颜色
FixModeIcon.Fill = _isFixMode ? Brushes.Yellow : Brushes.White;
// 显示提示
if (_isFixMode)
{
MessageBox.Show("已进入固定模式,您可以拖动应用图标调整位置。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
#endregion
}
}
@@ -0,0 +1,589 @@
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn
{
/// <summary>
/// 超级启动台插件
/// </summary>
public class SuperLauncherPlugin : PluginBase
{
#region
public override string Name => "超级启动台";
public override string Description => "在浮动栏添加一个启动台按钮,可快速启动常用应用程序。";
public override Version Version => new Version(1, 0, 1);
public override string Author => "ICC CE 团队";
public override bool IsBuiltIn => true;
#endregion
#region
/// <summary>
/// 启动台配置
/// </summary>
public LauncherConfig Config { get; private set; }
/// <summary>
/// 启动台应用程序列表
/// </summary>
public ObservableCollection<LauncherItem> LauncherItems { get; private set; }
/// <summary>
/// 启动台按钮
/// </summary>
private LauncherButton _launcherButton;
/// <summary>
/// 启动台窗口
/// </summary>
private LauncherWindow _launcherWindow;
/// <summary>
/// 配置文件路径
/// </summary>
private readonly string _configPath = Path.Combine(App.RootPath, "PluginConfigs", "SuperLauncher.json");
/// <summary>
/// 标记是否已添加到浮动栏
/// </summary>
private bool _isAddedToFloatingBar;
#endregion
#region
public override void Initialize()
{
try
{
base.Initialize();
// 创建配置目录
string configDir = Path.Combine(App.RootPath, "PluginConfigs");
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
// 加载配置
LoadConfig();
LogHelper.WriteLogToFile("超级启动台插件已初始化");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
public override void Enable()
{
try
{
if (IsEnabled) return; // 防止重复启用
// 创建启动台按钮
if (_launcherButton == null)
{
_launcherButton = new LauncherButton(this);
LogHelper.WriteLogToFile("超级启动台按钮已创建");
}
// 添加启动台按钮到浮动栏
AddLauncherButtonToFloatingBar();
// 设置启用状态
base.Enable();
// 保存插件配置
SavePluginSettings();
LogHelper.WriteLogToFile("超级启动台插件已启用");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启用超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
public override void Disable()
{
try
{
if (!IsEnabled) return; // 防止重复禁用
// 从浮动栏移除启动台按钮
RemoveLauncherButtonFromFloatingBar();
// 如果启动台窗口打开,则关闭
if (_launcherWindow != null && _launcherWindow.IsVisible)
{
_launcherWindow.Close();
_launcherWindow = null;
}
// 设置禁用状态
base.Disable();
// 保存插件配置
SavePluginSettings();
LogHelper.WriteLogToFile("超级启动台插件已禁用");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"禁用超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
public override UserControl GetSettingsView()
{
return new LauncherSettingsControl(this);
}
public override void Cleanup()
{
// 保存配置
SaveConfig();
// 从浮动栏移除启动台按钮
RemoveLauncherButtonFromFloatingBar();
// 如果启动台窗口打开,则关闭
if (_launcherWindow != null && _launcherWindow.IsVisible)
{
_launcherWindow.Close();
_launcherWindow = null;
}
base.Cleanup();
}
/// <summary>
/// 保存插件设置
/// </summary>
public override void SavePluginSettings()
{
try
{
// 确保配置已加载
if (Config == null)
{
LoadConfig();
}
// 更新其他设置,但不更改插件启用状态
// 保存配置
SaveConfig();
LogHelper.WriteLogToFile("超级启动台插件设置已保存");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存超级启动台插件设置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
/// <summary>
/// 加载配置
/// </summary>
private void LoadConfig()
{
try
{
if (File.Exists(_configPath))
{
string json = File.ReadAllText(_configPath);
Config = JsonConvert.DeserializeObject<LauncherConfig>(json) ?? CreateDefaultConfig();
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items ?? new List<LauncherItem>());
// 注意:不再根据配置更改插件启用状态
// 插件状态由PluginManager统一管理
}
else
{
Config = CreateDefaultConfig();
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items);
SaveConfig();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载超级启动台配置时出错: {ex.Message}", LogHelper.LogType.Error);
Config = CreateDefaultConfig();
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items);
}
}
/// <summary>
/// 保存配置
/// </summary>
public void SaveConfig()
{
try
{
// 同步LauncherItems到Config
Config.Items = new List<LauncherItem>(LauncherItems);
// 序列化并保存配置
string json = JsonConvert.SerializeObject(Config, Formatting.Indented);
File.WriteAllText(_configPath, json);
LogHelper.WriteLogToFile("超级启动台配置已保存");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存超级启动台配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 创建默认配置
/// </summary>
private LauncherConfig CreateDefaultConfig()
{
var config = new LauncherConfig
{
ButtonPosition = LauncherButtonPosition.Right,
// 不再使用IsEnabled,插件状态由PluginManager管理
Items = new List<LauncherItem>
{
new LauncherItem
{
Name = "资源管理器",
Path = @"C:\Windows\explorer.exe",
IsVisible = true,
Position = 0
}
}
};
return config;
}
#endregion
#region
/// <summary>
/// 将启动台按钮添加到浮动栏
/// </summary>
private void AddLauncherButtonToFloatingBar()
{
try
{
// 如果已经添加,先移除
if (_isAddedToFloatingBar)
{
RemoveLauncherButtonFromFloatingBar();
_isAddedToFloatingBar = false;
}
// 获取主窗口实例
var mainWindow = Application.Current.MainWindow;
if (mainWindow == null)
{
LogHelper.WriteLogToFile("未找到主窗口实例,无法添加启动台按钮", LogHelper.LogType.Error);
return;
}
// 创建启动台按钮
_launcherButton = new LauncherButton(this);
var buttonElement = _launcherButton.Element;
// 查找浮动栏
var floatingBar = mainWindow.FindName("StackPanelFloatingBar") as Panel;
if (floatingBar == null)
{
// 如果直接查找失败,则尝试遍历可视树查找
Panel floatingBarPanelFromTree = null;
FindStackPanelFloatingBar(mainWindow, ref floatingBarPanelFromTree);
floatingBar = floatingBarPanelFromTree;
}
if (floatingBar == null)
{
LogHelper.WriteLogToFile("未找到浮动栏,无法添加启动台按钮", LogHelper.LogType.Error);
return;
}
// 添加启动台按钮到浮动栏
if (Config.ButtonPosition == LauncherButtonPosition.Left)
{
floatingBar.Children.Insert(0, buttonElement);
LogHelper.WriteLogToFile("启动台按钮已添加到浮动栏左侧");
}
else
{
floatingBar.Children.Add(buttonElement);
LogHelper.WriteLogToFile("启动台按钮已添加到浮动栏右侧");
}
_isAddedToFloatingBar = true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加启动台按钮到浮动栏时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
/// <summary>
/// 递归查找StackPanelFloatingBar
/// </summary>
private void FindStackPanelFloatingBar(DependencyObject parent, ref Panel result)
{
if (parent == null || result != null) return;
try
{
// 检查当前对象是否为我们要找的面板
if (parent is Panel panel && panel.Name == "StackPanelFloatingBar")
{
result = panel;
return;
}
// 获取子元素数量
int childCount = VisualTreeHelper.GetChildrenCount(parent);
// 遍历所有子元素
for (int i = 0; i < childCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
FindStackPanelFloatingBar(child, ref result);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"查找StackPanelFloatingBar时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从浮动栏移除启动台按钮
/// </summary>
private void RemoveLauncherButtonFromFloatingBar()
{
try
{
if (!_isAddedToFloatingBar || _launcherButton == null)
{
return;
}
// 获取主窗口实例
var mainWindow = Application.Current.MainWindow;
if (mainWindow == null)
{
LogHelper.WriteLogToFile("未找到主窗口实例,无法移除启动台按钮", LogHelper.LogType.Error);
return;
}
// 获取按钮元素
var buttonElement = _launcherButton.Element;
// 查找浮动栏
var floatingBar = mainWindow.FindName("StackPanelFloatingBar") as Panel;
if (floatingBar == null)
{
// 如果直接查找失败,则尝试遍历可视树查找
Panel floatingBarPanelFromTree = null;
FindStackPanelFloatingBar(mainWindow, ref floatingBarPanelFromTree);
floatingBar = floatingBarPanelFromTree;
}
if (floatingBar == null)
{
LogHelper.WriteLogToFile("未找到浮动栏,无法移除启动台按钮", LogHelper.LogType.Error);
return;
}
// 从浮动栏移除启动台按钮
if (floatingBar.Children.Contains(buttonElement))
{
floatingBar.Children.Remove(buttonElement);
LogHelper.WriteLogToFile("启动台按钮已从浮动栏移除");
}
_isAddedToFloatingBar = false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"移除启动台按钮时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
/// <summary>
/// 更新启动台按钮位置
/// </summary>
public void UpdateButtonPosition()
{
try
{
// 如果按钮已添加到浮动栏,重新添加以更新位置
if (_isAddedToFloatingBar)
{
RemoveLauncherButtonFromFloatingBar();
AddLauncherButtonToFloatingBar();
LogHelper.WriteLogToFile($"启动台按钮位置已更新为: {Config.ButtonPosition}");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新启动台按钮位置时出错: {ex.Message}", LogHelper.LogType.Error);
LogHelper.NewLog(ex);
}
}
#endregion
#region
/// <summary>
/// 显示启动台窗口
/// </summary>
/// <param name="buttonPosition">按钮在屏幕上的位置</param>
public void ShowLauncherWindow(Point buttonPosition)
{
try
{
// 如果窗口已存在,关闭它
if (_launcherWindow != null && _launcherWindow.IsVisible)
{
_launcherWindow.Close();
_launcherWindow = null;
return;
}
// 创建新的启动台窗口
_launcherWindow = new LauncherWindow(this);
// 计算窗口位置,使其位于按钮上方
PositionLauncherWindow(_launcherWindow, buttonPosition);
// 显示窗口
_launcherWindow.Show();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示启动台窗口时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 设置启动台窗口位置
/// </summary>
/// <param name="window">启动台窗口</param>
/// <param name="buttonPosition">按钮在屏幕上的位置</param>
private void PositionLauncherWindow(LauncherWindow window, Point buttonPosition)
{
// 确保窗口已加载
if (window.ActualWidth == 0 || window.ActualHeight == 0)
{
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
// 设置窗口加载完成后的位置
window.Loaded += (s, e) =>
{
// 窗口位于按钮上方居中
double left = buttonPosition.X - (window.ActualWidth / 2);
double top = buttonPosition.Y - window.ActualHeight - 10; // 在按钮上方留出一些间距
// 确保窗口在屏幕内
left = Math.Max(0, Math.Min(left, SystemParameters.WorkArea.Width - window.ActualWidth));
top = Math.Max(0, Math.Min(top, SystemParameters.WorkArea.Height - window.ActualHeight));
window.Left = left;
window.Top = top;
};
}
else
{
// 窗口位于按钮上方居中
double left = buttonPosition.X - (window.ActualWidth / 2);
double top = buttonPosition.Y - window.ActualHeight - 10; // 在按钮上方留出一些间距
// 确保窗口在屏幕内
left = Math.Max(0, Math.Min(left, SystemParameters.WorkArea.Width - window.ActualWidth));
top = Math.Max(0, Math.Min(top, SystemParameters.WorkArea.Height - window.ActualHeight));
window.Left = left;
window.Top = top;
}
}
/// <summary>
/// 添加应用到启动台
/// </summary>
/// <param name="item">启动台项</param>
public void AddLauncherItem(LauncherItem item)
{
// 如果项目数量已达上限,则不添加
if (LauncherItems.Count >= 40)
{
MessageBox.Show("启动台项目数量已达上限(40个)!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// 寻找合适的位置
if (item.Position < 0)
{
item.Position = FindNextAvailablePosition();
}
// 添加项目并保存配置
LauncherItems.Add(item);
SaveConfig();
}
/// <summary>
/// 查找下一个可用位置
/// </summary>
private int FindNextAvailablePosition()
{
// 获取已使用的位置列表
var usedPositions = new HashSet<int>();
foreach (var item in LauncherItems)
{
usedPositions.Add(item.Position);
}
// 查找第一个可用位置
for (int i = 0; i < 40; i++)
{
if (!usedPositions.Contains(i))
{
return i;
}
}
// 如果所有位置都已使用,则返回0
return 0;
}
#endregion
}
}
@@ -0,0 +1,92 @@
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 增强的插件基类,提供对插件服务的访问和基本实现
/// </summary>
public abstract class EnhancedPluginBase : PluginBase, IEnhancedPlugin
{
/// <summary>
/// 插件服务实例
/// </summary>
public IPluginService PluginService { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
protected EnhancedPluginBase()
{
PluginService = PluginServiceManager.Instance;
}
/// <summary>
/// 插件启动时调用,在Initialize之后
/// </summary>
public virtual void OnStartup()
{
LogHelper.WriteLogToFile($"插件 {Name} 已启动");
}
/// <summary>
/// 插件关闭时调用,在Cleanup之前
/// </summary>
public virtual void OnShutdown()
{
LogHelper.WriteLogToFile($"插件 {Name} 正在关闭");
}
/// <summary>
/// 获取插件的菜单项
/// </summary>
/// <returns>菜单项集合</returns>
public virtual MenuItem[] GetMenuItems()
{
return new MenuItem[0];
}
/// <summary>
/// 获取插件的工具栏按钮
/// </summary>
/// <returns>工具栏按钮集合</returns>
public virtual Button[] GetToolbarButtons()
{
return new Button[0];
}
/// <summary>
/// 获取插件的状态栏信息
/// </summary>
/// <returns>状态栏信息</returns>
public virtual string GetStatusBarInfo()
{
return $"{Name} v{Version} - {(IsEnabled ? "" : "")}";
}
/// <summary>
/// 插件配置变更时调用
/// </summary>
public virtual void OnConfigurationChanged()
{
LogHelper.WriteLogToFile($"插件 {Name} 配置已变更");
}
/// <summary>
/// 重写初始化方法,调用OnStartup
/// </summary>
public override void Initialize()
{
base.Initialize();
OnStartup();
}
/// <summary>
/// 重写清理方法,调用OnShutdown
/// </summary>
public override void Cleanup()
{
OnShutdown();
base.Cleanup();
}
}
}
@@ -0,0 +1,241 @@
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 增强的插件基类 V2,提供对三个专门服务接口的访问
/// 插件开发者可以根据需要选择性地使用这些服务
/// </summary>
public abstract class EnhancedPluginBaseV2 : PluginBase, IEnhancedPlugin
{
/// <summary>
/// 获取服务实例
/// </summary>
public IGetService GetService { get; private set; }
/// <summary>
/// 窗口服务实例
/// </summary>
public IWindowService WindowService { get; private set; }
/// <summary>
/// 操作服务实例
/// </summary>
public IActionService ActionService { get; private set; }
/// <summary>
/// 插件服务实例(兼容性)
/// </summary>
public IPluginService PluginService { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
protected EnhancedPluginBaseV2()
{
// 初始化所有服务实例
PluginService = PluginServiceManager.Instance;
GetService = PluginServiceManager.Instance;
WindowService = PluginServiceManager.Instance;
ActionService = PluginServiceManager.Instance;
}
/// <summary>
/// 插件启动时调用,在Initialize之后
/// </summary>
public virtual void OnStartup()
{
LogHelper.WriteLogToFile($"插件 {Name} 已启动");
}
/// <summary>
/// 插件关闭时调用,在Cleanup之前
/// </summary>
public virtual void OnShutdown()
{
LogHelper.WriteLogToFile($"插件 {Name} 正在关闭");
}
/// <summary>
/// 获取插件的菜单项
/// </summary>
/// <returns>菜单项集合</returns>
public virtual MenuItem[] GetMenuItems()
{
return new MenuItem[0];
}
/// <summary>
/// 获取插件的工具栏按钮
/// </summary>
/// <returns>工具栏按钮集合</returns>
public virtual Button[] GetToolbarButtons()
{
return new Button[0];
}
/// <summary>
/// 获取插件的状态栏信息
/// </summary>
/// <returns>状态栏信息</returns>
public virtual string GetStatusBarInfo()
{
return $"{Name} v{Version} - {(IsEnabled ? "" : "")}";
}
/// <summary>
/// 插件配置变更时调用
/// </summary>
public virtual void OnConfigurationChanged()
{
LogHelper.WriteLogToFile($"插件 {Name} 配置已变更");
}
#region 便
/// <summary>
/// 显示通知消息
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="type">消息类型</param>
protected void ShowNotification(string message, NotificationType type = NotificationType.Info)
{
WindowService.ShowNotification(message, type);
}
/// <summary>
/// 显示确认对话框
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="title">标题</param>
/// <returns>用户选择结果</returns>
protected bool ShowConfirmDialog(string message, string title = "确认")
{
return WindowService.ShowConfirmDialog(message, title);
}
/// <summary>
/// 显示输入对话框
/// </summary>
/// <param name="message">提示消息</param>
/// <param name="title">标题</param>
/// <param name="defaultValue">默认值</param>
/// <returns>用户输入内容</returns>
protected string ShowInputDialog(string message, string title = "输入", string defaultValue = "")
{
return WindowService.ShowInputDialog(message, title, defaultValue);
}
/// <summary>
/// 获取系统设置
/// </summary>
/// <typeparam name="T">设置类型</typeparam>
/// <param name="key">设置键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>设置值</returns>
protected T GetSetting<T>(string key, T defaultValue = default(T))
{
return GetService.GetSetting(key, defaultValue);
}
/// <summary>
/// 设置系统设置
/// </summary>
/// <typeparam name="T">设置类型</typeparam>
/// <param name="key">设置键</param>
/// <param name="value">设置值</param>
protected void SetSetting<T>(string key, T value)
{
ActionService.SetSetting(key, value);
}
/// <summary>
/// 保存设置
/// </summary>
protected void SaveSettings()
{
ActionService.SaveSettings();
}
/// <summary>
/// 清除当前画布
/// </summary>
protected void ClearCanvas()
{
ActionService.ClearCanvas();
}
/// <summary>
/// 撤销操作
/// </summary>
protected void Undo()
{
ActionService.Undo();
}
/// <summary>
/// 重做操作
/// </summary>
protected void Redo()
{
ActionService.Redo();
}
/// <summary>
/// 检查是否可以撤销
/// </summary>
protected bool CanUndo => GetService.CanUndo;
/// <summary>
/// 检查是否可以重做
/// </summary>
protected bool CanRedo => GetService.CanRedo;
/// <summary>
/// 获取当前绘制模式
/// </summary>
protected int CurrentDrawingMode => GetService.CurrentDrawingMode;
/// <summary>
/// 设置绘制模式
/// </summary>
/// <param name="mode">绘制模式</param>
protected void SetDrawingMode(int mode)
{
ActionService.SetDrawingMode(mode);
}
/// <summary>
/// 注册事件处理器
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="handler">事件处理器</param>
protected void RegisterEventHandler(string eventName, System.EventHandler handler)
{
ActionService.RegisterEventHandler(eventName, handler);
}
/// <summary>
/// 注销事件处理器
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="handler">事件处理器</param>
protected void UnregisterEventHandler(string eventName, System.EventHandler handler)
{
ActionService.UnregisterEventHandler(eventName, handler);
}
/// <summary>
/// 触发事件
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="sender">事件发送者</param>
/// <param name="args">事件参数</param>
protected void TriggerEvent(string eventName, object sender, System.EventArgs args)
{
ActionService.TriggerEvent(eventName, sender, args);
}
#endregion
}
}
@@ -0,0 +1,296 @@
using System;
using System.Windows.Media;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 操作服务接口,统一所有执行操作相关的方法
/// </summary>
public interface IActionService
{
#region
/// <summary>
/// 清除当前画布
/// </summary>
void ClearCanvas();
/// <summary>
/// 清除所有画布
/// </summary>
void ClearAllCanvases();
/// <summary>
/// 添加新页面
/// </summary>
void AddNewPage();
/// <summary>
/// 删除当前页面
/// </summary>
void DeleteCurrentPage();
/// <summary>
/// 切换到指定页面
/// </summary>
/// <param name="pageIndex">页面索引</param>
void SwitchToPage(int pageIndex);
/// <summary>
/// 切换到下一页
/// </summary>
void NextPage();
/// <summary>
/// 切换到上一页
/// </summary>
void PreviousPage();
#endregion
#region
/// <summary>
/// 设置绘制模式
/// </summary>
/// <param name="mode">绘制模式</param>
void SetDrawingMode(int mode);
/// <summary>
/// 设置笔触宽度
/// </summary>
/// <param name="width">宽度</param>
void SetInkWidth(double width);
/// <summary>
/// 设置笔触颜色
/// </summary>
/// <param name="color">颜色</param>
void SetInkColor(Color color);
/// <summary>
/// 设置高亮笔宽度
/// </summary>
/// <param name="width">宽度</param>
void SetHighlighterWidth(double width);
/// <summary>
/// 设置橡皮擦大小
/// </summary>
/// <param name="size">大小</param>
void SetEraserSize(int size);
/// <summary>
/// 设置橡皮擦类型
/// </summary>
/// <param name="type">类型</param>
void SetEraserType(int type);
/// <summary>
/// 设置橡皮擦形状
/// </summary>
/// <param name="shape">形状</param>
void SetEraserShape(int shape);
/// <summary>
/// 设置笔触透明度
/// </summary>
/// <param name="alpha">透明度</param>
void SetInkAlpha(double alpha);
/// <summary>
/// 设置笔触样式
/// </summary>
/// <param name="style">样式</param>
void SetInkStyle(int style);
/// <summary>
/// 设置背景颜色
/// </summary>
/// <param name="color">颜色</param>
void SetBackgroundColor(string color);
#endregion
#region
/// <summary>
/// 保存画布内容
/// </summary>
/// <param name="filePath">文件路径</param>
void SaveCanvas(string filePath);
/// <summary>
/// 加载画布内容
/// </summary>
/// <param name="filePath">文件路径</param>
void LoadCanvas(string filePath);
/// <summary>
/// 导出为图片
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="format">图片格式</param>
void ExportAsImage(string filePath, string format);
/// <summary>
/// 导出为PDF
/// </summary>
/// <param name="filePath">文件路径</param>
void ExportAsPDF(string filePath);
#endregion
#region
/// <summary>
/// 撤销操作
/// </summary>
void Undo();
/// <summary>
/// 重做操作
/// </summary>
void Redo();
#endregion
#region
/// <summary>
/// 全选
/// </summary>
void SelectAll();
/// <summary>
/// 取消选择
/// </summary>
void DeselectAll();
/// <summary>
/// 删除选中内容
/// </summary>
void DeleteSelected();
/// <summary>
/// 复制选中内容
/// </summary>
void CopySelected();
/// <summary>
/// 剪切选中内容
/// </summary>
void CutSelected();
/// <summary>
/// 粘贴内容
/// </summary>
void Paste();
#endregion
#region
/// <summary>
/// 设置系统设置
/// </summary>
/// <typeparam name="T">设置类型</typeparam>
/// <param name="key">设置键</param>
/// <param name="value">设置值</param>
void SetSetting<T>(string key, T value);
/// <summary>
/// 保存设置到文件
/// </summary>
void SaveSettings();
/// <summary>
/// 从文件加载设置
/// </summary>
void LoadSettings();
/// <summary>
/// 重置设置为默认值
/// </summary>
void ResetSettings();
#endregion
#region
/// <summary>
/// 启用插件
/// </summary>
/// <param name="pluginName">插件名称</param>
void EnablePlugin(string pluginName);
/// <summary>
/// 禁用插件
/// </summary>
/// <param name="pluginName">插件名称</param>
void DisablePlugin(string pluginName);
/// <summary>
/// 卸载插件
/// </summary>
/// <param name="pluginName">插件名称</param>
void UnloadPlugin(string pluginName);
#endregion
#region
/// <summary>
/// 注册事件处理器
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="handler">事件处理器</param>
void RegisterEventHandler(string eventName, EventHandler handler);
/// <summary>
/// 注销事件处理器
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="handler">事件处理器</param>
void UnregisterEventHandler(string eventName, EventHandler handler);
/// <summary>
/// 触发事件
/// </summary>
/// <param name="eventName">事件名称</param>
/// <param name="sender">事件发送者</param>
/// <param name="args">事件参数</param>
void TriggerEvent(string eventName, object sender, EventArgs args);
#endregion
#region
/// <summary>
/// 重启应用程序
/// </summary>
void RestartApplication();
/// <summary>
/// 退出应用程序
/// </summary>
void ExitApplication();
/// <summary>
/// 检查更新
/// </summary>
void CheckForUpdates();
/// <summary>
/// 打开帮助文档
/// </summary>
void OpenHelpDocument();
/// <summary>
/// 打开关于页面
/// </summary>
void OpenAboutPage();
#endregion
}
}
@@ -0,0 +1,178 @@
using System;
using System.IO;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// ICCPP 插件适配器,用于加载和管理 .iccpp 格式的插件
/// </summary>
public class ICCPPPluginAdapter : PluginBase
{
private readonly byte[] _pluginData;
private readonly string _pluginPath;
private readonly string _pluginName;
private readonly Version _pluginVersion;
private bool _isInitialized;
/// <summary>
/// 创建 ICCPP 插件适配器
/// </summary>
/// <param name="pluginPath">插件文件路径</param>
/// <param name="pluginData">插件文件数据</param>
public ICCPPPluginAdapter(string pluginPath, byte[] pluginData)
{
_pluginPath = pluginPath;
_pluginData = pluginData;
PluginPath = pluginPath;
// 从文件名获取插件名称
_pluginName = Path.GetFileNameWithoutExtension(pluginPath);
_pluginVersion = new Version(1, 0, 0); // 默认版本
// 尝试从插件数据中读取更多信息
TryReadPluginMetadata();
}
public ICCPPPluginAdapter()
{
_pluginPath = string.Empty;
_pluginData = new byte[0];
PluginPath = string.Empty;
_pluginName = "ICCPPPlugin";
_pluginVersion = new Version(1, 0, 0);
// 可选:初始化其他字段
}
/// <summary>
/// 尝试从插件数据中读取元数据
/// </summary>
private void TryReadPluginMetadata()
{
try
{
// 这里可以根据 .iccpp 文件的实际格式解析元数据
// 例如,如果文件有特定的头部结构,可以在这里解析
// 示例:如果前100字节包含元数据
if (_pluginData.Length > 100)
{
// 解析元数据的代码...
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"解析插件 {_pluginName} 元数据时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#region IPlugin
/// <summary>
/// 插件名称
/// </summary>
public override string Name => _pluginName;
/// <summary>
/// 插件描述
/// </summary>
public override string Description => $"{_pluginName} (ICCPP 格式插件)";
/// <summary>
/// 插件版本
/// </summary>
public override Version Version => _pluginVersion;
/// <summary>
/// 插件作者
/// </summary>
public override string Author => "未知";
/// <summary>
/// 是否为内置插件
/// </summary>
public override bool IsBuiltIn => false;
/// <summary>
/// 初始化插件
/// </summary>
public override void Initialize()
{
if (_isInitialized) return;
try
{
// 这里可以添加 .iccpp 插件的初始化逻辑
// 例如,根据文件格式加载特定资源
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已初始化");
_isInitialized = true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 启用插件
/// </summary>
public override void Enable()
{
if (IsEnabled) return;
try
{
// 这里可以添加 .iccpp 插件的启用逻辑
// 例如,加载动态库、注册事件等
base.Enable(); // 设置启用状态并触发事件
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已启用");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 禁用插件
/// </summary>
public override void Disable()
{
if (!IsEnabled) return;
try
{
// 这里可以添加 .iccpp 插件的禁用逻辑
// 例如,卸载动态库、注销事件等
base.Disable(); // 设置禁用状态并触发事件
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已禁用");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"禁用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 清理插件资源
/// </summary>
public override void Cleanup()
{
try
{
// 这里可以添加 .iccpp 插件的清理逻辑
// 例如,释放资源等
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已清理资源");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理 ICCPP 插件 {Name} 资源时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
}
@@ -0,0 +1,48 @@
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 增强的插件接口,提供对插件服务的访问
/// </summary>
public interface IEnhancedPlugin : IPlugin
{
/// <summary>
/// 获取插件服务实例
/// </summary>
IPluginService PluginService { get; }
/// <summary>
/// 插件启动时调用,在Initialize之后
/// </summary>
void OnStartup();
/// <summary>
/// 插件关闭时调用,在Cleanup之前
/// </summary>
void OnShutdown();
/// <summary>
/// 获取插件的菜单项
/// </summary>
/// <returns>菜单项集合</returns>
MenuItem[] GetMenuItems();
/// <summary>
/// 获取插件的工具栏按钮
/// </summary>
/// <returns>工具栏按钮集合</returns>
Button[] GetToolbarButtons();
/// <summary>
/// 获取插件的状态栏信息
/// </summary>
/// <returns>状态栏信息</returns>
string GetStatusBarInfo();
/// <summary>
/// 插件配置变更时调用
/// </summary>
void OnConfigurationChanged();
}
}
+214
View File
@@ -0,0 +1,214 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 获取服务接口,统一所有获取类的方法
/// </summary>
public interface IGetService
{
#region UI获取
/// <summary>
/// 获取主窗口引用
/// </summary>
Window MainWindow { get; }
/// <summary>
/// 获取当前画布
/// </summary>
InkCanvas CurrentCanvas { get; }
/// <summary>
/// 获取所有画布页面
/// </summary>
List<Canvas> AllCanvasPages { get; }
/// <summary>
/// 获取当前页面索引
/// </summary>
int CurrentPageIndex { get; }
/// <summary>
/// 获取当前页面数量
/// </summary>
int TotalPageCount { get; }
/// <summary>
/// 获取浮动工具栏
/// </summary>
FrameworkElement FloatingToolBar { get; }
/// <summary>
/// 获取左侧面板
/// </summary>
FrameworkElement LeftPanel { get; }
/// <summary>
/// 获取右侧面板
/// </summary>
FrameworkElement RightPanel { get; }
/// <summary>
/// 获取顶部面板
/// </summary>
FrameworkElement TopPanel { get; }
/// <summary>
/// 获取底部面板
/// </summary>
FrameworkElement BottomPanel { get; }
#endregion
#region
/// <summary>
/// 获取当前绘制模式
/// </summary>
int CurrentDrawingMode { get; }
/// <summary>
/// 获取当前笔触宽度
/// </summary>
double CurrentInkWidth { get; }
/// <summary>
/// 获取当前笔触颜色
/// </summary>
Color CurrentInkColor { get; }
/// <summary>
/// 获取当前高亮笔宽度
/// </summary>
double CurrentHighlighterWidth { get; }
/// <summary>
/// 获取当前橡皮擦大小
/// </summary>
int CurrentEraserSize { get; }
/// <summary>
/// 获取当前橡皮擦类型
/// </summary>
int CurrentEraserType { get; }
/// <summary>
/// 获取当前橡皮擦形状
/// </summary>
int CurrentEraserShape { get; }
/// <summary>
/// 获取当前笔触透明度
/// </summary>
double CurrentInkAlpha { get; }
/// <summary>
/// 获取当前笔触样式
/// </summary>
int CurrentInkStyle { get; }
/// <summary>
/// 获取当前背景颜色
/// </summary>
string CurrentBackgroundColor { get; }
#endregion
#region
/// <summary>
/// 获取当前主题模式
/// </summary>
bool IsDarkTheme { get; }
/// <summary>
/// 获取当前是否为白板模式
/// </summary>
bool IsWhiteboardMode { get; }
/// <summary>
/// 获取当前是否为PPT模式
/// </summary>
bool IsPPTMode { get; }
/// <summary>
/// 获取当前是否为全屏模式
/// </summary>
bool IsFullScreenMode { get; }
/// <summary>
/// 获取当前是否为画板模式
/// </summary>
bool IsCanvasMode { get; }
/// <summary>
/// 获取当前是否为选择模式
/// </summary>
bool IsSelectionMode { get; }
/// <summary>
/// 获取当前是否为擦除模式
/// </summary>
bool IsEraserMode { get; }
/// <summary>
/// 获取当前是否为形状绘制模式
/// </summary>
bool IsShapeDrawingMode { get; }
/// <summary>
/// 获取当前是否为高亮模式
/// </summary>
bool IsHighlighterMode { get; }
#endregion
#region
/// <summary>
/// 获取是否可以撤销
/// </summary>
bool CanUndo { get; }
/// <summary>
/// 获取是否可以重做
/// </summary>
bool CanRedo { get; }
#endregion
#region
/// <summary>
/// 获取系统设置
/// </summary>
/// <typeparam name="T">设置类型</typeparam>
/// <param name="key">设置键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>设置值</returns>
T GetSetting<T>(string key, T defaultValue = default(T));
#endregion
#region
/// <summary>
/// 获取所有已加载的插件
/// </summary>
/// <returns>插件列表</returns>
List<IPlugin> GetAllPlugins();
/// <summary>
/// 获取指定插件
/// </summary>
/// <param name="pluginName">插件名称</param>
/// <returns>插件实例</returns>
IPlugin GetPlugin(string pluginName);
#endregion
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 定义插件的基本接口
/// </summary>
public interface IPlugin
{
/// <summary>
/// 插件名称
/// </summary>
string Name { get; }
/// <summary>
/// 插件描述
/// </summary>
string Description { get; }
/// <summary>
/// 插件版本
/// </summary>
Version Version { get; }
/// <summary>
/// 插件作者
/// </summary>
string Author { get; }
/// <summary>
/// 是否为内置插件
/// </summary>
bool IsBuiltIn { get; }
/// <summary>
/// 初始化插件
/// 此方法在插件加载时被调用,用于执行一些初始化工作
/// </summary>
void Initialize();
/// <summary>
/// 启用插件
/// 此方法在插件被用户或系统启用时调用,激活插件功能
/// </summary>
void Enable();
/// <summary>
/// 禁用插件
/// 此方法在插件被用户或系统禁用时调用,停用插件功能
/// </summary>
void Disable();
/// <summary>
/// 获取插件设置界面
/// 此方法返回插件的设置界面控件,用于展示在设置窗口
/// </summary>
/// <returns>插件设置界面</returns>
UserControl GetSettingsView();
/// <summary>
/// 插件卸载时的清理工作
/// 此方法在插件被卸载前调用,用于释放资源和执行清理
/// </summary>
void Cleanup();
}
}
@@ -0,0 +1,38 @@
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 插件服务接口,提供对软件内部功能的访问
/// 继承自三个专门的服务接口:获取服务、窗口服务、操作服务
/// </summary>
public interface IPluginService : IGetService, IWindowService, IActionService
{
// 这个接口现在继承自三个专门的服务接口
// 所有方法都在子接口中定义,这里不需要重复定义
}
/// <summary>
/// 通知类型枚举
/// </summary>
public enum NotificationType
{
/// <summary>
/// 信息
/// </summary>
Info,
/// <summary>
/// 成功
/// </summary>
Success,
/// <summary>
/// 警告
/// </summary>
Warning,
/// <summary>
/// 错误
/// </summary>
Error
}
}
@@ -0,0 +1,152 @@
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 窗口服务接口,统一所有窗口操作相关的方法
/// </summary>
public interface IWindowService
{
#region
/// <summary>
/// 显示设置窗口
/// </summary>
void ShowSettingsWindow();
/// <summary>
/// 隐藏设置窗口
/// </summary>
void HideSettingsWindow();
/// <summary>
/// 显示插件设置窗口
/// </summary>
void ShowPluginSettingsWindow();
/// <summary>
/// 隐藏插件设置窗口
/// </summary>
void HidePluginSettingsWindow();
/// <summary>
/// 显示帮助窗口
/// </summary>
void ShowHelpWindow();
/// <summary>
/// 隐藏帮助窗口
/// </summary>
void HideHelpWindow();
/// <summary>
/// 显示关于窗口
/// </summary>
void ShowAboutWindow();
/// <summary>
/// 隐藏关于窗口
/// </summary>
void HideAboutWindow();
#endregion
#region
/// <summary>
/// 显示通知消息
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="type">消息类型</param>
void ShowNotification(string message, NotificationType type = NotificationType.Info);
/// <summary>
/// 显示确认对话框
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="title">标题</param>
/// <returns>用户选择结果</returns>
bool ShowConfirmDialog(string message, string title = "确认");
/// <summary>
/// 显示输入对话框
/// </summary>
/// <param name="message">提示消息</param>
/// <param name="title">标题</param>
/// <param name="defaultValue">默认值</param>
/// <returns>用户输入内容</returns>
string ShowInputDialog(string message, string title = "输入", string defaultValue = "");
#endregion
#region
/// <summary>
/// 设置窗口全屏状态
/// </summary>
/// <param name="isFullScreen">是否全屏</param>
void SetFullScreen(bool isFullScreen);
/// <summary>
/// 设置窗口置顶状态
/// </summary>
/// <param name="isTopMost">是否置顶</param>
void SetTopMost(bool isTopMost);
/// <summary>
/// 设置窗口可见性
/// </summary>
/// <param name="isVisible">是否可见</param>
void SetWindowVisibility(bool isVisible);
/// <summary>
/// 最小化窗口
/// </summary>
void MinimizeWindow();
/// <summary>
/// 最大化窗口
/// </summary>
void MaximizeWindow();
/// <summary>
/// 恢复窗口
/// </summary>
void RestoreWindow();
/// <summary>
/// 关闭窗口
/// </summary>
void CloseWindow();
#endregion
#region
/// <summary>
/// 设置窗口位置
/// </summary>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
void SetWindowPosition(double x, double y);
/// <summary>
/// 设置窗口大小
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
void SetWindowSize(double width, double height);
/// <summary>
/// 获取窗口位置
/// </summary>
/// <returns>窗口位置</returns>
(double x, double y) GetWindowPosition();
/// <summary>
/// 获取窗口大小
/// </summary>
/// <returns>窗口大小</returns>
(double width, double height) GetWindowSize();
#endregion
}
}
+161
View File
@@ -0,0 +1,161 @@
using System;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 插件基类,提供基本实现
/// </summary>
public abstract class PluginBase : IPlugin
{
/// <summary>
/// 插件状态(私有字段)
/// </summary>
private bool _isEnabled;
/// <summary>
/// 插件状态(公共属性)
/// </summary>
public bool IsEnabled
{
get => _isEnabled;
protected set
{
if (_isEnabled != value)
{
_isEnabled = value;
OnEnabledStateChanged(value);
}
}
}
/// <summary>
/// 插件ID
/// </summary>
public string Id { get; protected set; }
/// <summary>
/// 插件路径
/// </summary>
public string PluginPath { get; set; }
/// <summary>
/// 插件名称
/// </summary>
public abstract string Name { get; }
/// <summary>
/// 插件描述
/// </summary>
public abstract string Description { get; }
/// <summary>
/// 插件版本
/// </summary>
public abstract Version Version { get; }
/// <summary>
/// 插件作者
/// </summary>
public abstract string Author { get; }
/// <summary>
/// 是否为内置插件
/// </summary>
public virtual bool IsBuiltIn => false;
/// <summary>
/// 状态变更事件
/// </summary>
public event EventHandler<bool> EnabledStateChanged;
/// <summary>
/// 初始化插件
/// </summary>
public virtual void Initialize()
{
Id = GetType().FullName;
// 添加日志,记录插件名称
try
{
string name = Name;
LogHelper.WriteLogToFile($"初始化插件: ID={Id}, 名称={name ?? ""}");
if (string.IsNullOrEmpty(name))
{
LogHelper.WriteLogToFile($"警告: 插件 {Id} 的名称为空", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取插件名称时出错: {ex.Message}", LogHelper.LogType.Error);
}
LogHelper.WriteLogToFile($"插件 {Name} 已初始化");
}
/// <summary>
/// 启用插件
/// </summary>
public virtual void Enable()
{
if (!IsEnabled)
{
IsEnabled = true;
LogHelper.WriteLogToFile($"插件 {Name} 已启用");
}
}
/// <summary>
/// 禁用插件
/// </summary>
public virtual void Disable()
{
if (IsEnabled)
{
IsEnabled = false;
LogHelper.WriteLogToFile($"插件 {Name} 已禁用");
}
}
/// <summary>
/// 获取插件设置界面
/// </summary>
/// <returns>插件设置界面</returns>
public virtual UserControl GetSettingsView()
{
// 默认返回空设置页面
return new UserControl();
}
/// <summary>
/// 插件卸载时的清理工作
/// </summary>
public virtual void Cleanup()
{
LogHelper.WriteLogToFile($"插件 {Name} 已卸载");
}
/// <summary>
/// 保存插件自身的设置
/// 注意:此方法仅用于保存插件的特定设置,不应影响插件启用/禁用状态
/// 插件启用状态由PluginManager统一管理
/// </summary>
public virtual void SavePluginSettings()
{
// 默认实现不做任何事情
// 子类可以重写此方法,将自身设置保存到配置文件中
LogHelper.WriteLogToFile($"插件 {Name} 设置已保存", LogHelper.LogType.Event);
}
/// <summary>
/// 触发状态变更事件
/// </summary>
/// <param name="isEnabled">是否启用</param>
protected virtual void OnEnabledStateChanged(bool isEnabled)
{
EnabledStateChanged?.Invoke(this, isEnabled);
}
}
}
@@ -0,0 +1,273 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 插件配置管理器,允许插件管理自己的配置
/// </summary>
public class PluginConfigurationManager
{
private static readonly string PluginConfigDirectory = Path.Combine(App.RootPath, "PluginConfigs");
private static readonly Dictionary<string, Dictionary<string, object>> _pluginConfigs = new Dictionary<string, Dictionary<string, object>>();
private static readonly object _lockObject = new object();
static PluginConfigurationManager()
{
// 确保配置目录存在
if (!Directory.Exists(PluginConfigDirectory))
{
Directory.CreateDirectory(PluginConfigDirectory);
}
}
/// <summary>
/// 获取插件配置值
/// </summary>
/// <typeparam name="T">配置值类型</typeparam>
/// <param name="pluginName">插件名称</param>
/// <param name="key">配置键</param>
/// <param name="defaultValue">默认值</param>
/// <returns>配置值</returns>
public static T GetConfiguration<T>(string pluginName, string key, T defaultValue = default(T))
{
lock (_lockObject)
{
try
{
if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig))
{
if (pluginConfig.TryGetValue(key, out var value))
{
if (value is T typedValue)
{
return typedValue;
}
// 尝试类型转换
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
return defaultValue;
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
return defaultValue;
}
}
/// <summary>
/// 设置插件配置值
/// </summary>
/// <typeparam name="T">配置值类型</typeparam>
/// <param name="pluginName">插件名称</param>
/// <param name="key">配置键</param>
/// <param name="value">配置值</param>
public static void SetConfiguration<T>(string pluginName, string key, T value)
{
lock (_lockObject)
{
try
{
if (!_pluginConfigs.ContainsKey(pluginName))
{
_pluginConfigs[pluginName] = new Dictionary<string, object>();
}
_pluginConfigs[pluginName][key] = value;
// 异步保存配置
Task.Run(() => SavePluginConfiguration(pluginName));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 删除插件配置
/// </summary>
/// <param name="pluginName">插件名称</param>
/// <param name="key">配置键</param>
public static void RemoveConfiguration(string pluginName, string key)
{
lock (_lockObject)
{
try
{
if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig))
{
if (pluginConfig.Remove(key))
{
// 异步保存配置
Task.Run(() => SavePluginConfiguration(pluginName));
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"删除插件 {pluginName} 配置 {key} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 获取插件的所有配置
/// </summary>
/// <param name="pluginName">插件名称</param>
/// <returns>配置字典</returns>
public static Dictionary<string, object> GetAllConfigurations(string pluginName)
{
lock (_lockObject)
{
if (_pluginConfigs.TryGetValue(pluginName, out var pluginConfig))
{
return new Dictionary<string, object>(pluginConfig);
}
return new Dictionary<string, object>();
}
}
/// <summary>
/// 清除插件的所有配置
/// </summary>
/// <param name="pluginName">插件名称</param>
public static void ClearAllConfigurations(string pluginName)
{
lock (_lockObject)
{
try
{
if (_pluginConfigs.Remove(pluginName))
{
// 删除配置文件
string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json");
if (File.Exists(configFile))
{
File.Delete(configFile);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除插件 {pluginName} 所有配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 加载插件配置
/// </summary>
/// <param name="pluginName">插件名称</param>
public static void LoadPluginConfiguration(string pluginName)
{
try
{
string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json");
if (File.Exists(configFile))
{
string json = File.ReadAllText(configFile);
var config = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
lock (_lockObject)
{
_pluginConfigs[pluginName] = config ?? new Dictionary<string, object>();
}
LogHelper.WriteLogToFile($"已加载插件 {pluginName} 的配置");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载插件 {pluginName} 配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 保存插件配置
/// </summary>
/// <param name="pluginName">插件名称</param>
private static void SavePluginConfiguration(string pluginName)
{
try
{
Dictionary<string, object> pluginConfig;
lock (_lockObject)
{
if (!_pluginConfigs.TryGetValue(pluginName, out pluginConfig))
{
return;
}
}
string configFile = Path.Combine(PluginConfigDirectory, $"{pluginName}.json");
string json = JsonConvert.SerializeObject(pluginConfig, Formatting.Indented);
File.WriteAllText(configFile, json);
LogHelper.WriteLogToFile($"已保存插件 {pluginName} 的配置");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存插件 {pluginName} 配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 加载所有插件的配置
/// </summary>
public static void LoadAllPluginConfigurations()
{
try
{
if (Directory.Exists(PluginConfigDirectory))
{
string[] configFiles = Directory.GetFiles(PluginConfigDirectory, "*.json");
foreach (string configFile in configFiles)
{
string pluginName = Path.GetFileNameWithoutExtension(configFile);
LoadPluginConfiguration(pluginName);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载所有插件配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 保存所有插件的配置
/// </summary>
public static void SaveAllPluginConfigurations()
{
try
{
lock (_lockObject)
{
foreach (string pluginName in _pluginConfigs.Keys)
{
SavePluginConfiguration(pluginName);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存所有插件配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,509 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 插件服务管理器,实现IPluginService接口,提供对软件内部功能的访问
/// </summary>
public class PluginServiceManager : IPluginService
{
private static PluginServiceManager _instance;
private MainWindow _mainWindow;
private Dictionary<string, EventHandler> _eventHandlers;
/// <summary>
/// 单例实例
/// </summary>
public static PluginServiceManager Instance
{
get
{
if (_instance == null)
{
_instance = new PluginServiceManager();
}
return _instance;
}
}
private PluginServiceManager()
{
_eventHandlers = new Dictionary<string, EventHandler>();
}
/// <summary>
/// 设置主窗口引用
/// </summary>
/// <param name="mainWindow">主窗口实例</param>
public void SetMainWindow(MainWindow mainWindow)
{
_mainWindow = mainWindow;
}
#region UI访问
public Window MainWindow => _mainWindow;
public InkCanvas CurrentCanvas => null; // 暂时返回null,避免访问权限问题
public List<Canvas> AllCanvasPages => new List<Canvas>(); // 暂时返回空列表
public int CurrentPageIndex => 0; // 暂时返回0
public int TotalPageCount => 0; // 暂时返回0
public FrameworkElement FloatingToolBar => _mainWindow?.ViewboxFloatingBar;
public FrameworkElement LeftPanel => _mainWindow?.BlackboardLeftSide;
public FrameworkElement RightPanel => _mainWindow?.BlackboardRightSide;
public FrameworkElement TopPanel => _mainWindow?.BorderTools;
public FrameworkElement BottomPanel => _mainWindow?.BorderSettings;
#endregion
#region
public int CurrentDrawingMode => 0; // 暂时返回0
public double CurrentInkWidth => 2.5; // 暂时返回默认值
public Color CurrentInkColor => Colors.Black; // 暂时返回默认值
public double CurrentHighlighterWidth => 20.0; // 暂时返回默认值
public int CurrentEraserSize => 2; // 暂时返回默认值
public int CurrentEraserType => 0; // 暂时返回默认值
public int CurrentEraserShape => 0; // 暂时返回默认值
public double CurrentInkAlpha => 255.0; // 暂时返回默认值
public int CurrentInkStyle => 0; // 暂时返回默认值
public string CurrentBackgroundColor => "#162924"; // 暂时返回默认值
#endregion
#region
public bool IsDarkTheme => false; // 暂时返回默认值
public bool IsWhiteboardMode => false; // 暂时返回默认值
public bool IsPPTMode => false; // 暂时返回默认值
public bool IsFullScreenMode => false; // 暂时返回默认值
public bool IsCanvasMode => true; // 暂时返回默认值
public bool IsSelectionMode => false; // 暂时返回默认值
public bool IsEraserMode => false; // 暂时返回默认值
public bool IsShapeDrawingMode => false; // 暂时返回默认值
public bool IsHighlighterMode => false; // 暂时返回默认值
#endregion
#region IGetService
public bool CanUndo => false; // 暂时返回默认值
public bool CanRedo => false; // 暂时返回默认值
public T GetSetting<T>(string key, T defaultValue = default(T))
{
// 暂时不实现,避免访问权限问题
return defaultValue;
}
public List<IPlugin> GetAllPlugins()
{
return new List<IPlugin>(PluginManager.Instance.Plugins);
}
public IPlugin GetPlugin(string pluginName)
{
return PluginManager.Instance.Plugins.FirstOrDefault(p => p.Name == pluginName);
}
#endregion
#region IWindowService
public void ShowSettingsWindow()
{
// 暂时不实现,避免访问权限问题
}
public void HideSettingsWindow()
{
// 暂时不实现,避免访问权限问题
}
public void ShowPluginSettingsWindow()
{
// 暂时不实现,避免访问权限问题
}
public void HidePluginSettingsWindow()
{
// 暂时不实现,避免访问权限问题
}
public void ShowHelpWindow()
{
// 暂时不实现,避免访问权限问题
}
public void HideHelpWindow()
{
// 暂时不实现,避免访问权限问题
}
public void ShowAboutWindow()
{
// 暂时不实现,避免访问权限问题
}
public void HideAboutWindow()
{
// 暂时不实现,避免访问权限问题
}
public void ShowNotification(string message, NotificationType type = NotificationType.Info)
{
// 暂时不实现,避免访问权限问题
}
public bool ShowConfirmDialog(string message, string title = "确认")
{
// 暂时不实现,避免访问权限问题
return false;
}
public string ShowInputDialog(string message, string title = "输入", string defaultValue = "")
{
// 暂时不实现,避免访问权限问题
return defaultValue;
}
public void SetFullScreen(bool isFullScreen)
{
// 暂时不实现,避免访问权限问题
}
public void SetTopMost(bool isTopMost)
{
// 暂时不实现,避免访问权限问题
}
public void SetWindowVisibility(bool isVisible)
{
// 暂时不实现,避免访问权限问题
}
public void MinimizeWindow()
{
// 暂时不实现,避免访问权限问题
}
public void MaximizeWindow()
{
// 暂时不实现,避免访问权限问题
}
public void RestoreWindow()
{
// 暂时不实现,避免访问权限问题
}
public void CloseWindow()
{
// 暂时不实现,避免访问权限问题
}
public void SetWindowPosition(double x, double y)
{
// 暂时不实现,避免访问权限问题
}
public void SetWindowSize(double width, double height)
{
// 暂时不实现,避免访问权限问题
}
public (double x, double y) GetWindowPosition()
{
// 暂时不实现,避免访问权限问题
return (0, 0);
}
public (double width, double height) GetWindowSize()
{
// 暂时不实现,避免访问权限问题
return (800, 600);
}
#endregion
#region IActionService
public void ClearCanvas()
{
// 暂时不实现,避免访问权限问题
}
public void ClearAllCanvases()
{
// 暂时不实现,避免访问权限问题
}
public void AddNewPage()
{
// 暂时不实现,避免访问权限问题
}
public void DeleteCurrentPage()
{
// 暂时不实现,避免访问权限问题
}
public void SwitchToPage(int pageIndex)
{
// 暂时不实现,避免访问权限问题
}
public void NextPage()
{
// 暂时不实现,避免访问权限问题
}
public void PreviousPage()
{
// 暂时不实现,避免访问权限问题
}
public void SetDrawingMode(int mode)
{
// 暂时不实现,避免访问权限问题
}
public void SetInkWidth(double width)
{
// 暂时不实现,避免访问权限问题
}
public void SetInkColor(Color color)
{
// 暂时不实现,避免访问权限问题
}
public void SetHighlighterWidth(double width)
{
// 暂时不实现,避免访问权限问题
}
public void SetEraserSize(int size)
{
// 暂时不实现,避免访问权限问题
}
public void SetEraserType(int type)
{
// 暂时不实现,避免访问权限问题
}
public void SetEraserShape(int shape)
{
// 暂时不实现,避免访问权限问题
}
public void SetInkAlpha(double alpha)
{
// 暂时不实现,避免访问权限问题
}
public void SetInkStyle(int style)
{
// 暂时不实现,避免访问权限问题
}
public void SetBackgroundColor(string color)
{
// 暂时不实现,避免访问权限问题
}
public void SaveCanvas(string filePath)
{
// 暂时不实现,避免访问权限问题
}
public void LoadCanvas(string filePath)
{
// 暂时不实现,避免访问权限问题
}
public void ExportAsImage(string filePath, string format)
{
// 暂时不实现,避免访问权限问题
}
public void ExportAsPDF(string filePath)
{
// 暂时不实现,避免访问权限问题
}
public void Undo()
{
// 暂时不实现,避免访问权限问题
}
public void Redo()
{
// 暂时不实现,避免访问权限问题
}
public void SelectAll()
{
// 暂时不实现,避免访问权限问题
}
public void DeselectAll()
{
// 暂时不实现,避免访问权限问题
}
public void DeleteSelected()
{
// 暂时不实现,避免访问权限问题
}
public void CopySelected()
{
// 暂时不实现,避免访问权限问题
}
public void CutSelected()
{
// 暂时不实现,避免访问权限问题
}
public void Paste()
{
// 暂时不实现,避免访问权限问题
}
public void SetSetting<T>(string key, T value)
{
// 暂时不实现,避免访问权限问题
}
public void SaveSettings()
{
// 暂时不实现,避免访问权限问题
}
public void LoadSettings()
{
// 暂时不实现,避免访问权限问题
}
public void ResetSettings()
{
// 暂时不实现,避免访问权限问题
}
public void EnablePlugin(string pluginName)
{
var plugin = GetPlugin(pluginName);
if (plugin != null)
{
PluginManager.Instance.TogglePlugin(plugin, true);
}
}
public void DisablePlugin(string pluginName)
{
var plugin = GetPlugin(pluginName);
if (plugin != null)
{
PluginManager.Instance.TogglePlugin(plugin, false);
}
}
public void UnloadPlugin(string pluginName)
{
var plugin = GetPlugin(pluginName);
if (plugin != null)
{
PluginManager.Instance.UnloadPlugin(plugin);
}
}
public void RegisterEventHandler(string eventName, EventHandler handler)
{
if (!_eventHandlers.ContainsKey(eventName))
{
_eventHandlers[eventName] = handler;
}
else
{
_eventHandlers[eventName] += handler;
}
}
public void UnregisterEventHandler(string eventName, EventHandler handler)
{
if (_eventHandlers.ContainsKey(eventName))
{
_eventHandlers[eventName] -= handler;
}
}
public void TriggerEvent(string eventName, object sender, EventArgs args)
{
if (_eventHandlers.ContainsKey(eventName))
{
_eventHandlers[eventName]?.Invoke(sender, args);
}
}
public void RestartApplication()
{
// 暂时不实现,避免访问权限问题
}
public void ExitApplication()
{
// 暂时不实现,避免访问权限问题
}
public void CheckForUpdates()
{
// 暂时不实现,避免访问权限问题
}
public void OpenHelpDocument()
{
// 暂时不实现,避免访问权限问题
}
public void OpenAboutPage()
{
// 暂时不实现,避免访问权限问题
}
#endregion
}
}
@@ -0,0 +1,276 @@
using System;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// 插件模板,用于开发者参考
/// 注意:实际开发时,请将此类移到单独的程序集中
/// </summary>
public class PluginTemplate : PluginBase
{
#region
/// <summary>
/// 插件名称
/// </summary>
public override string Name => "插件模板";
/// <summary>
/// 插件描述
/// </summary>
public override string Description => "这是一个插件开发模板,用于开发者参考。";
/// <summary>
/// 插件版本
/// </summary>
public override Version Version => new Version(1, 0, 0);
/// <summary>
/// 插件作者
/// </summary>
public override string Author => "Your Name";
/// <summary>
/// 是否为内置插件(外部插件请返回false)
/// </summary>
public override bool IsBuiltIn => false;
#endregion
#region
/// <summary>
/// 插件初始化
/// 在这里进行插件的初始化工作,如加载配置、注册事件等
/// </summary>
public override void Initialize()
{
// 先调用基类方法,这样会设置插件ID和记录日志
base.Initialize();
// TODO: 在这里进行插件初始化工作
// 示例:记录初始化信息
LogHelper.WriteLogToFile($"插件 {Name} 开始初始化");
// 示例:加载配置
LoadConfig();
// 示例:注册自定义事件
// MainWindow.Instance.SomeEvent += OnSomeEvent;
LogHelper.WriteLogToFile($"插件 {Name} 初始化完成");
}
/// <summary>
/// 启用插件
/// 在这里激活插件功能
/// </summary>
public override void Enable()
{
// 先调用基类方法,这样会设置插件状态和记录日志
base.Enable();
// TODO: 在这里启用插件功能
LogHelper.WriteLogToFile($"插件 {Name} 已启用");
}
/// <summary>
/// 禁用插件
/// 在这里停用插件功能
/// </summary>
public override void Disable()
{
// 先调用基类方法,这样会设置插件状态和记录日志
base.Disable();
// TODO: 在这里禁用插件功能
LogHelper.WriteLogToFile($"插件 {Name} 已禁用");
}
/// <summary>
/// 清理资源
/// 在插件卸载时调用,清理资源
/// </summary>
public override void Cleanup()
{
// TODO: 在这里清理插件资源
// 示例:取消注册事件
// MainWindow.Instance.SomeEvent -= OnSomeEvent;
// 示例:保存配置
SaveConfig();
// 最后调用基类方法
base.Cleanup();
}
#endregion
#region
/// <summary>
/// 加载插件配置
/// </summary>
private void LoadConfig()
{
try
{
// TODO: 从文件或其他位置加载配置
// 示例:
// string configPath = Path.Combine(App.RootPath, "PluginConfigs", "YourPluginName.json");
// if (File.Exists(configPath))
// {
// string json = File.ReadAllText(configPath);
// YourConfig = Newtonsoft.Json.JsonConvert.DeserializeObject<YourConfigClass>(json);
// }
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载插件配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 保存插件配置
/// </summary>
private void SaveConfig()
{
try
{
// TODO: 保存配置到文件或其他位置
// 示例:
// string configDir = Path.Combine(App.RootPath, "PluginConfigs");
// if (!Directory.Exists(configDir))
// {
// Directory.CreateDirectory(configDir);
// }
// string configPath = Path.Combine(configDir, "YourPluginName.json");
// string json = Newtonsoft.Json.JsonConvert.SerializeObject(YourConfig, Newtonsoft.Json.Formatting.Indented);
// File.WriteAllText(configPath, json);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存插件配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
/// <summary>
/// 获取插件设置界面
/// </summary>
/// <returns>插件设置界面</returns>
public override UserControl GetSettingsView()
{
// 创建插件设置界面
return new PluginTemplateSettingsControl();
}
#endregion
#region
// TODO: 在这里添加插件的具体功能方法
/// <summary>
/// 示例方法:执行一些功能
/// </summary>
public void DoSomething()
{
if (!IsEnabled) return;
try
{
// TODO: 实现你的功能
MessageBox.Show("插件功能执行示例", "插件模板", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"执行插件功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
/// <summary>
/// 插件设置控件
/// </summary>
public class PluginTemplateSettingsControl : UserControl
{
public PluginTemplateSettingsControl()
{
// 创建设置界面布局
var panel = new StackPanel
{
Margin = new Thickness(10)
};
// 添加标题
panel.Children.Add(new TextBlock
{
Text = "插件模板设置",
FontSize = 16,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 0, 0, 10)
});
// 添加说明文字
panel.Children.Add(new TextBlock
{
Text = "这是一个示例设置界面,你可以在这里添加自己的设置控件。",
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 15)
});
// 添加示例设置选项
var checkBox = new CheckBox
{
Content = "启用某项功能",
Margin = new Thickness(0, 0, 0, 10)
};
panel.Children.Add(checkBox);
// 添加文本输入框
panel.Children.Add(new TextBlock
{
Text = "设置项:",
Margin = new Thickness(0, 5, 0, 5)
});
panel.Children.Add(new TextBox
{
Margin = new Thickness(0, 0, 0, 10),
Width = 200,
HorizontalAlignment = HorizontalAlignment.Left
});
// 添加按钮
var button = new Button
{
Content = "保存设置",
Padding = new Thickness(10, 5, 10, 5),
Margin = new Thickness(0, 10, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left
};
button.Click += (sender, e) =>
{
MessageBox.Show("设置已保存!", "插件模板", MessageBoxButton.OK, MessageBoxImage.Information);
};
panel.Children.Add(button);
// 设置控件内容
Content = panel;
}
}
}
+156
View File
@@ -0,0 +1,156 @@
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using Point = System.Windows.Point;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 屏幕检测帮助类 - 用于检测窗口所在的屏幕和屏幕信息
/// </summary>
public static class ScreenDetectionHelper
{
/// <summary>
/// 获取窗口所在的屏幕
/// </summary>
/// <param name="window">要检测的窗口</param>
/// <returns>窗口所在的屏幕,如果无法检测则返回主屏幕</returns>
public static Screen GetWindowScreen(Window window)
{
try
{
if (window == null)
return Screen.PrimaryScreen;
// 获取窗口的句柄
var hwndSource = PresentationSource.FromVisual(window) as HwndSource;
if (hwndSource == null)
return Screen.PrimaryScreen;
// 获取窗口在屏幕上的位置
var windowRect = GetWindowScreenBounds(window);
// 查找与窗口重叠最多的屏幕
Screen targetScreen = null;
double maxIntersection = 0;
foreach (var screen in Screen.AllScreens)
{
var intersection = Rectangle.Intersect(windowRect, screen.Bounds);
if (intersection.Width * intersection.Height > maxIntersection)
{
maxIntersection = intersection.Width * intersection.Height;
targetScreen = screen;
}
}
return targetScreen ?? Screen.PrimaryScreen;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"检测窗口屏幕时出错: {ex.Message}", LogHelper.LogType.Warning);
return Screen.PrimaryScreen;
}
}
/// <summary>
/// 获取窗口在屏幕坐标系中的边界
/// </summary>
/// <param name="window">要检测的窗口</param>
/// <returns>窗口的屏幕边界</returns>
private static Rectangle GetWindowScreenBounds(Window window)
{
try
{
// 获取窗口左上角在屏幕上的位置
var topLeft = window.PointToScreen(new Point(0, 0));
// 获取窗口右下角在屏幕上的位置
var bottomRight = window.PointToScreen(new Point(window.ActualWidth, window.ActualHeight));
return new Rectangle(
(int)topLeft.X,
(int)topLeft.Y,
(int)(bottomRight.X - topLeft.X),
(int)(bottomRight.Y - topLeft.Y));
}
catch
{
// 如果无法获取精确位置,返回窗口的Left和Top
return new Rectangle(
(int)window.Left,
(int)window.Top,
(int)window.Width,
(int)window.Height);
}
}
/// <summary>
/// 检查是否有多个屏幕
/// </summary>
/// <returns>如果有多个屏幕返回true,否则返回false</returns>
public static bool HasMultipleScreens()
{
try
{
return Screen.AllScreens.Length > 1;
}
catch
{
return false;
}
}
/// <summary>
/// 获取主屏幕
/// </summary>
/// <returns>主屏幕</returns>
public static Screen GetPrimaryScreen()
{
try
{
return Screen.PrimaryScreen;
}
catch
{
return null;
}
}
/// <summary>
/// 获取所有屏幕信息
/// </summary>
/// <returns>所有屏幕的数组</returns>
public static Screen[] GetAllScreens()
{
try
{
return Screen.AllScreens;
}
catch
{
return new Screen[] { Screen.PrimaryScreen };
}
}
/// <summary>
/// 检查窗口是否在主屏幕上
/// </summary>
/// <param name="window">要检查的窗口</param>
/// <returns>如果窗口在主屏幕上返回true,否则返回false</returns>
public static bool IsWindowOnPrimaryScreen(Window window)
{
try
{
var windowScreen = GetWindowScreen(window);
return windowScreen == Screen.PrimaryScreen;
}
catch
{
return true; // 出错时假设在主屏幕
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More