Compare commits

...

474 Commits

Author SHA1 Message Date
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
464 changed files with 31007 additions and 152286 deletions
+93
View File
@@ -0,0 +1,93 @@
{
"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": "Hydro11451",
"name": "Hydrogen",
"avatar_url": "https://avatars.githubusercontent.com/u/214308559?v=4",
"profile": "http://hydro11451.qzz.io",
"contributions": [
"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"
]
}
]
}
-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: false
- type: textarea
id: expected
attributes:
label: 期望结果 | Expected Behavior
description: 你期望的正确行为或结果 | What did you expect to happen?
validations:
required: false
- 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: false
- 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
+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.6.4
1.7.7.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

+3 -1
View File
@@ -1,2 +1,4 @@
<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></wpf:ResourceDictionary>
File diff suppressed because one or more lines are too long
+522 -87
View File
@@ -1,20 +1,26 @@
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.Win32;
using System.Security; // 添加SecurityException所需命名空间
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using Window = System.Windows.Window;
using System.Collections.Generic;
using Timer = System.Threading.Timer;
namespace Ink_Canvas
{
@@ -23,43 +29,401 @@ namespace Ink_Canvas
/// </summary>
public partial class App : Application
{
System.Threading.Mutex mutex;
Mutex mutex;
public static string[] StartArgs = null;
public static string[] StartArgs;
public static string RootPath = Environment.GetEnvironmentVariable("APPDATA") + "\\Ink Canvas\\";
// 新增:保存看门狗进程对象
private static Process watchdogProcess = null;
private static Process watchdogProcess;
// 新增:标记是否为软件内主动退出
public static bool IsAppExitByUser = false;
public static bool IsAppExitByUser;
// 新增:退出信号文件路径
private static string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + System.Diagnostics.Process.GetCurrentProcess().Id + ".flag");
private static string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + Process.GetCurrentProcess().Id + ".flag");
// 新增:崩溃日志文件路径
private static string crashLogFile = Path.Combine(Environment.GetEnvironmentVariable("APPDATA"), "Ink Canvas", "crash_logs");
// 新增:进程ID
private static int currentProcessId = Process.GetCurrentProcess().Id;
// 新增:应用启动时间
private static DateTime appStartTime = DateTime.Now;
// 新增:最后一次错误信息
private static string lastErrorMessage = string.Empty;
// 新增:是否已初始化崩溃监听器
private static bool crashListenersInitialized;
public App()
{
this.Startup += new StartupEventHandler(App_Startup);
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
// 配置TLS协议以支持Windows 7
ConfigureTlsForWindows7();
// 如果是看门狗子进程,直接进入看门狗主循环并终止主流程
var args = Environment.GetCommandLineArgs();
if (args.Length >= 2 && args[1] == "--watchdog")
{
RunWatchdogIfNeeded();
Environment.Exit(0);
return;
}
// 启动时优先同步设置,确保CrashAction为最新
SyncCrashActionFromSettings();
Startup += App_Startup;
DispatcherUnhandledException += App_DispatcherUnhandledException;
StartHeartbeatMonitor();
StartWatchdogIfNeeded();
this.Exit += App_Exit; // 注册退出事件
// 新增:初始化全局异常和进程结束处理
InitializeCrashListeners();
// 仅在崩溃后操作为静默重启时才启动看门狗
if (CrashAction == CrashActionType.SilentRestart)
{
StartWatchdogIfNeeded();
}
Exit += App_Exit; // 注册退出事件
}
// 新增:配置TLS协议以支持Windows 7
private void ConfigureTlsForWindows7()
{
try
{
// 检测操作系统版本
var osVersion = Environment.OSVersion;
bool isWindows7 = osVersion.Version.Major == 6 && osVersion.Version.Minor == 1;
if (isWindows7)
{
LogHelper.WriteLogToFile("检测到Windows 7系统,配置TLS协议支持");
// 启用所有TLS版本以支持Windows 7
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
// 配置ServicePointManager以支持Windows 7
ServicePointManager.DefaultConnectionLimit = 10;
ServicePointManager.Expect100Continue = false;
ServicePointManager.UseNagleAlgorithm = false;
LogHelper.WriteLogToFile("TLS协议配置完成,已启用TLS 1.2/1.1/1.0支持");
}
else
{
// 对于更新的Windows版本,不进行任何TLS配置,使用系统默认设置
LogHelper.WriteLogToFile($"检测到Windows版本: {osVersion.VersionString},使用系统默认TLS配置");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"配置TLS协议时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
// 新增:初始化崩溃监听器
private void InitializeCrashListeners()
{
if (crashListenersInitialized) return;
try
{
// 确保崩溃日志目录存在
if (!Directory.Exists(crashLogFile))
{
Directory.CreateDirectory(crashLogFile);
}
// 注册非UI线程未处理异常处理程序
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
// 注册控制台Ctrl+C等终止信号处理
Console.CancelKeyPress += Console_CancelKeyPress;
// 注册系统会话结束事件(关机、注销等)
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
// 注册进程退出处理程序
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
// 尝试注册Windows关闭消息监听
SetConsoleCtrlHandler(ConsoleCtrlHandler, true);
// 如果系统支持,添加Windows Management Instrumentation监听器
try
{
// 使用反射动态加载和调用WMI
TrySetupWmiMonitoring();
}
catch (Exception wmiEx)
{
LogHelper.WriteLogToFile($"设置WMI进程监控失败: {wmiEx.Message}", LogHelper.LogType.Warning);
}
crashListenersInitialized = true;
LogHelper.WriteLogToFile("已初始化崩溃监听器");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化崩溃监听器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 新增:动态加载WMI监控(避免直接引用System.Management
private void TrySetupWmiMonitoring()
{
try
{
// 检查System.Management程序集是否可用
var assemblyName = "System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
var assembly = Assembly.Load(assemblyName);
if (assembly == null)
{
LogHelper.WriteLogToFile("未找到System.Management程序集,跳过WMI监控", LogHelper.LogType.Warning);
return;
}
// 使用反射创建WMI查询
var watcherType = assembly.GetType("System.Management.ManagementEventWatcher");
if (watcherType == null)
{
LogHelper.WriteLogToFile("未找到ManagementEventWatcher类型,跳过WMI监控", LogHelper.LogType.Warning);
return;
}
// 构建WMI查询字符串
string queryString = $"SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessId = {currentProcessId}";
// 创建ManagementEventWatcher实例
object watcher = Activator.CreateInstance(watcherType, queryString);
// 获取EventArrived事件信息
var eventInfo = watcherType.GetEvent("EventArrived");
if (eventInfo == null)
{
LogHelper.WriteLogToFile("未找到EventArrived事件,跳过WMI监控", LogHelper.LogType.Warning);
return;
}
// 创建委托并订阅事件
Type delegateType = eventInfo.EventHandlerType;
var handler = Delegate.CreateDelegate(delegateType, this, GetType().GetMethod("WmiEventHandler", BindingFlags.NonPublic | BindingFlags.Instance));
eventInfo.AddEventHandler(watcher, handler);
// 启动监听
var startMethod = watcherType.GetMethod("Start");
startMethod.Invoke(watcher, null);
LogHelper.WriteLogToFile("已成功启动WMI进程监控");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"动态加载WMI监控失败: {ex.Message}", LogHelper.LogType.Warning);
}
}
// WMI事件处理方法(通过反射调用)
private void WmiEventHandler(object sender, EventArgs e)
{
try
{
// 尝试从事件参数中提取信息
dynamic eventArgs = e;
dynamic newEvent = eventArgs.NewEvent;
if (newEvent != null)
{
dynamic targetInstance = newEvent["TargetInstance"];
if (targetInstance != null)
{
string processName = targetInstance["Name"]?.ToString() ?? "未知进程";
WriteCrashLog($"WMI检测到进程{processName}(ID:{currentProcessId})已终止");
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理WMI事件时出错: {ex.Message}", LogHelper.LogType.Warning);
}
}
// 新增:Windows控制台控制处理程序
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate handler, bool add);
private delegate bool ConsoleCtrlDelegate(int ctrlType);
private static bool ConsoleCtrlHandler(int ctrlType)
{
string eventType = "未知控制类型";
// 使用传统switch语句替代switch表达式
switch (ctrlType)
{
case 0:
eventType = "CTRL_C_EVENT";
break;
case 1:
eventType = "CTRL_BREAK_EVENT";
break;
case 2:
eventType = "CTRL_CLOSE_EVENT";
break;
case 5:
eventType = "CTRL_LOGOFF_EVENT";
break;
case 6:
eventType = "CTRL_SHUTDOWN_EVENT";
break;
default:
eventType = $"未知控制类型({ctrlType})";
break;
}
WriteCrashLog($"接收到系统控制信号: {eventType}");
// 返回true表示已处理该事件
return false;
}
// 新增:系统会话结束事件处理
private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
string reason = e.Reason == SessionEndReasons.Logoff ? "用户注销" : "系统关机";
WriteCrashLog($"系统会话即将结束: {reason}");
}
// 新增:控制台取消事件处理
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
WriteCrashLog($"接收到控制台中断信号: {e.SpecialKey}");
e.Cancel = true; // 取消默认处理
}
// 新增:处理非UI线程的未处理异常
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
var exception = e.ExceptionObject as Exception;
string errorMessage = exception?.ToString() ?? "未知异常";
lastErrorMessage = errorMessage;
WriteCrashLog($"捕获到未处理的异常: {errorMessage}");
if (e.IsTerminating)
{
WriteCrashLog("应用程序即将终止");
}
}
catch (Exception ex)
{
// 尝试在最后时刻记录错误
try
{
File.AppendAllText(
Path.Combine(crashLogFile, $"critical_error_{DateTime.Now:yyyyMMdd_HHmmss}.log"),
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 记录未处理异常时发生错误: {ex.Message}\r\n"
);
}
catch { }
}
}
// 新增:处理进程退出事件
private void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
TimeSpan runDuration = DateTime.Now - appStartTime;
WriteCrashLog($"应用程序退出,运行时长: {runDuration}");
// 如果有最后错误消息,记录到日志
if (!string.IsNullOrEmpty(lastErrorMessage))
{
WriteCrashLog($"最后错误信息: {lastErrorMessage}");
}
}
// 新增:记录崩溃日志
private static void WriteCrashLog(string message)
{
try
{
// 确保目录存在
if (!Directory.Exists(crashLogFile))
{
Directory.CreateDirectory(crashLogFile);
}
string logFileName = Path.Combine(crashLogFile, $"crash_{DateTime.Now:yyyyMMdd}.log");
// 收集系统状态信息
string memoryUsage = (Process.GetCurrentProcess().WorkingSet64 / (1024 * 1024)) + " MB";
string cpuTime = Process.GetCurrentProcess().TotalProcessorTime.ToString();
string processUptime = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString();
string statusInfo = $"[内存: {memoryUsage}, CPU时间: {cpuTime}, 运行时长: {processUptime}]";
// 写入日志
File.AppendAllText(
logFileName,
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [PID:{currentProcessId}] {message}\r\n{statusInfo}\r\n\r\n"
);
// 同时记录到主日志
LogHelper.WriteLogToFile(message, LogHelper.LogType.Error);
}
catch { }
}
// 增加字段保存崩溃后操作设置
public static CrashActionType CrashAction = CrashActionType.SilentRestart;
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
// 修正:允许静态调用
public static void SyncCrashActionFromSettings()
{
Ink_Canvas.MainWindow.ShowNewMessage("抱歉,出现未预期的异常,可能导致 InkCanvasForClass 运行不稳定。\n建议保存墨迹后重启应用。", true);
try
{
// 优先从 Settings.json 直接读取
var settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings.json");
if (File.Exists(settingsPath))
{
var json = File.ReadAllText(settingsPath);
dynamic obj = JsonConvert.DeserializeObject(json);
int crashAction = 0;
try { crashAction = (int)(obj["startup"]["crashAction"] ?? 0); } catch { }
CrashAction = (CrashActionType)crashAction;
}
// 兜底:从主窗口同步
else if (Ink_Canvas.MainWindow.Settings != null && Ink_Canvas.MainWindow.Settings.Startup != null)
{
CrashAction = (CrashActionType)Ink_Canvas.MainWindow.Settings.Startup.CrashAction;
}
}
catch { }
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
Ink_Canvas.MainWindow.ShowNewMessage("抱歉,出现未预期的异常,可能导致 InkCanvasForClass 运行不稳定。\n建议保存墨迹后重启应用。");
LogHelper.NewLog(e.Exception.ToString());
// 新增:记录到崩溃日志
lastErrorMessage = e.Exception.ToString();
WriteCrashLog($"UI线程未处理异常: {e.Exception}");
e.Handled = true;
// 修改:仅当非用户主动退出时才触发自动重启
SyncCrashActionFromSettings(); // 新增:崩溃时同步最新设置
if (CrashAction == CrashActionType.SilentRestart && !IsAppExitByUser)
{
StartupCount.Increment();
if (StartupCount.GetCount() >= 5)
{
MessageBox.Show("检测到程序已连续重启5次,已停止自动重启。请联系开发者或检查系统环境。", "重启次数过多", MessageBoxButton.OK, MessageBoxImage.Error);
StartupCount.Reset();
Environment.Exit(1);
}
try
{
string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
System.Diagnostics.Process.Start(exePath);
string exePath = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(exePath);
}
catch { }
Environment.Exit(1);
@@ -71,19 +435,47 @@ namespace Ink_Canvas
void App_Startup(object sender, StartupEventArgs e)
{
RunWatchdogIfNeeded();
/*if (!StoreHelper.IsStoreApp) */RootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
/*if (!StoreHelper.IsStoreApp) */
RootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
LogHelper.NewLog(string.Format("Ink Canvas Starting (Version: {0})", Assembly.GetExecutingAssembly().GetName().Version.ToString()));
LogHelper.NewLog(string.Format("Ink Canvas Starting (Version: {0})", Assembly.GetExecutingAssembly().GetName().Version));
// 在应用启动时自动释放IACore相关DLL
try
{
Helpers.IACoreDllExtractor.ExtractIACoreDlls();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放IACore DLL时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 记录应用启动(设备标识符)
DeviceIdentifier.RecordAppLaunch();
LogHelper.WriteLogToFile($"App | 设备ID: {DeviceIdentifier.GetDeviceId()}");
LogHelper.WriteLogToFile($"App | 使用频率: {DeviceIdentifier.GetUsageFrequency()}");
LogHelper.WriteLogToFile($"App | 更新优先级: {DeviceIdentifier.GetUpdatePriority()}");
bool ret;
mutex = new System.Threading.Mutex(true, "InkCanvasForClass", out ret);
mutex = new Mutex(true, "InkCanvasForClass CE", out ret);
if (!ret && !e.Args.Contains("-m")) //-m multiple
{
LogHelper.NewLog("Detected existing instance");
MessageBox.Show("已有一个程序实例正在运行");
LogHelper.NewLog("Ink Canvas automatically closed");
IsAppExitByUser = true; // 多开时标记为用户主动退出
// 写入退出信号,确保看门狗不会重启
try
{
StartupCount.Reset();
File.WriteAllText(watchdogExitSignalFile, "exit");
if (watchdogProcess != null && !watchdogProcess.HasExited)
{
watchdogProcess.Kill();
}
}
catch { }
Environment.Exit(0);
}
@@ -95,7 +487,7 @@ namespace Ink_Canvas
try
{
LogHelper.WriteLogToFile("开始Office注册表检测");
// 检查Office安装
if (!IsOfficeInstalled())
{
@@ -118,20 +510,20 @@ namespace Ink_Canvas
try
{
using (Microsoft.Win32.RegistryKey baseKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(regPath))
using (RegistryKey baseKey = Registry.CurrentUser.OpenSubKey(regPath))
{
if (baseKey == null)
{
LogHelper.WriteLogToFile($"注册表路径不存在: {regPath}", LogHelper.LogType.Warning);
// 尝试创建路径
try
try
{
using (Microsoft.Win32.RegistryKey createKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regPath, true))
using (RegistryKey createKey = Registry.CurrentUser.CreateSubKey(regPath, true))
{
if (createKey != null)
{
createKey.SetValue("DisableProtectedView", 1, Microsoft.Win32.RegistryValueKind.DWord);
LogHelper.WriteLogToFile($"创建并设置注册表路径: {regPath}", LogHelper.LogType.Info);
createKey.SetValue("DisableProtectedView", 1, RegistryValueKind.DWord);
LogHelper.WriteLogToFile($"创建并设置注册表路径: {regPath}");
}
}
}
@@ -145,23 +537,23 @@ namespace Ink_Canvas
// 备份路径更改为软件根目录下的saves/RegistryBackups文件夹
string backupPath = Path.Combine(RootPath, "saves", "RegistryBackups");
LogHelper.WriteLogToFile($"备份路径: {backupPath}");
if (!Directory.Exists(backupPath))
if (!Directory.Exists(backupPath))
{
Directory.CreateDirectory(backupPath);
LogHelper.WriteLogToFile($"创建备份目录: {backupPath}");
}
string backupFile = Path.Combine(backupPath, $"SecurityBackup_{version}_{DateTime.Now:yyyyMMddHHmmss}.reg");
LogHelper.WriteLogToFile($"创建备份文件: {backupFile}");
// 使用UTF8编码写入注册表文件
using (StreamWriter sw = new StreamWriter(backupFile, false, System.Text.Encoding.UTF8))
using (StreamWriter sw = new StreamWriter(backupFile, false, Encoding.UTF8))
{
sw.WriteLine("Windows Registry Editor Version 5.00\n");
sw.WriteLine();
sw.WriteLine($"[{Microsoft.Win32.Registry.CurrentUser.Name}\\{regPath}]");
sw.WriteLine($"[{Registry.CurrentUser.Name}\\{regPath}]");
foreach (string valueName in baseKey.GetValueNames())
{
object value = baseKey.GetValue(valueName);
@@ -170,13 +562,13 @@ namespace Ink_Canvas
}
}
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regPath, true))
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(regPath, true))
{
// 仅在值不存在或不等于1时更新
object currentValue = key.GetValue("DisableProtectedView");
if (currentValue == null || (int)currentValue != 1)
{
key.SetValue("DisableProtectedView", 1, Microsoft.Win32.RegistryValueKind.DWord);
key.SetValue("DisableProtectedView", 1, RegistryValueKind.DWord);
LogHelper.WriteLogToFile($"Office {version} 注册表值已设置: DisableProtectedView = 1");
}
else
@@ -189,7 +581,6 @@ namespace Ink_Canvas
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理Office版本 {version} 时出错: {ex.Message}", LogHelper.LogType.Error);
continue;
}
}
@@ -209,26 +600,26 @@ namespace Ink_Canvas
catch (Exception ex)
{
LogHelper.WriteLogToFile($"未知错误: {ex.GetType().FullName} - {ex.Message}", LogHelper.LogType.Error);
LogHelper.WriteLogToFile(ex.StackTrace, LogHelper.LogType.Info);
LogHelper.WriteLogToFile(ex.StackTrace);
}
}
private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
try
{
if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines == -1)
if (SystemInformation.MouseWheelScrollLines == -1)
e.Handled = false;
else
try
{
ScrollViewerEx SenderScrollViewer = (ScrollViewerEx)sender;
SenderScrollViewer.ScrollToVerticalOffset(SenderScrollViewer.VerticalOffset - e.Delta * 10 * System.Windows.Forms.SystemInformation.MouseWheelScrollLines / (double)120);
SenderScrollViewer.ScrollToVerticalOffset(SenderScrollViewer.VerticalOffset - e.Delta * 10 * SystemInformation.MouseWheelScrollLines / (double)120);
e.Handled = true;
}
catch { }
catch { }
}
catch { }
catch { }
}
// 新增:用于设置崩溃后操作类型
@@ -253,8 +644,16 @@ namespace Ink_Canvas
if ((DateTime.Now - lastHeartbeat).TotalSeconds > 10)
{
LogHelper.NewLog("检测到主线程无响应,自动重启。");
SyncCrashActionFromSettings(); // 新增:心跳检测时同步最新设置
if (CrashAction == CrashActionType.SilentRestart)
{
StartupCount.Increment();
if (StartupCount.GetCount() >= 5)
{
MessageBox.Show("检测到程序已连续重启5次,已停止自动重启。请联系开发者或检查系统环境。", "重启次数过多", MessageBoxButton.OK, MessageBoxImage.Error);
StartupCount.Reset();
Environment.Exit(1);
}
try
{
string exePath = Process.GetCurrentProcess().MainModule.FileName;
@@ -306,9 +705,21 @@ namespace Ink_Canvas
}
Thread.Sleep(2000);
}
// 主进程异常退出,自动重启
string exePath = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(exePath);
// 主进程异常退出,自动重启前判断崩溃后操作
SyncCrashActionFromSettings(); // 新增:同步设置
if (CrashAction == CrashActionType.SilentRestart)
{
StartupCount.Increment();
if (StartupCount.GetCount() >= 5)
{
MessageBox.Show("检测到程序已连续重启5次,已停止自动重启。请联系开发者或检查系统环境。", "重启次数过多", MessageBoxButton.OK, MessageBoxImage.Error);
StartupCount.Reset();
Environment.Exit(1);
}
string exePath = Process.GetCurrentProcess().MainModule.FileName;
Process.Start(exePath);
}
// CrashActionType.NoAction 时不重启,直接退出
}
catch { }
Environment.Exit(0);
@@ -320,9 +731,25 @@ namespace Ink_Canvas
// 仅在软件内主动退出时关闭看门狗,并写入退出信号
try
{
// 新增:记录应用退出状态
string exitType = IsAppExitByUser ? "用户主动退出" : "应用程序退出";
WriteCrashLog($"{exitType},退出代码: {e.ApplicationExitCode}");
// 记录应用退出(设备标识符)
try
{
DeviceIdentifier.RecordAppExit();
LogHelper.WriteLogToFile($"App | 应用运行时长: {(DateTime.Now - appStartTime).TotalMinutes:F1}分钟");
}
catch (Exception deviceEx)
{
LogHelper.WriteLogToFile($"记录设备标识符退出信息失败: {deviceEx.Message}", LogHelper.LogType.Error);
}
if (IsAppExitByUser)
{
// 写入退出信号文件,通知看门狗正常退出
StartupCount.Reset();
File.WriteAllText(watchdogExitSignalFile, "exit");
if (watchdogProcess != null && !watchdogProcess.HasExited)
{
@@ -330,7 +757,15 @@ namespace Ink_Canvas
}
}
}
catch { }
catch (Exception ex)
{
// 尝试记录最后的错误
try
{
LogHelper.WriteLogToFile($"退出处理时发生错误: {ex.Message}", LogHelper.LogType.Error);
}
catch { }
}
}
/// <summary>
@@ -342,60 +777,60 @@ namespace Ink_Canvas
{
// 检查多个可能的注册表路径
// 1. 检查传统的Office版本
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office"))
{
if (key != null && key.GetSubKeyNames().Any(name => name.Contains(".0")))
{
LogHelper.WriteLogToFile("检测到传统Office安装", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到传统Office安装");
return true;
}
}
// 2. 检查64位注册表中的Office
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\Microsoft\\Office"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\Microsoft\\Office"))
{
if (key != null && key.GetSubKeyNames().Any(name => name.Contains(".0")))
{
LogHelper.WriteLogToFile("检测到64位注册表中的Office安装", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到64位注册表中的Office安装");
return true;
}
}
// 3. 检查Office 365/Click-to-Run安装
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\ClickToRun"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\ClickToRun"))
{
if (key != null)
{
LogHelper.WriteLogToFile("检测到Office 365 Click-to-Run", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到Office 365 Click-to-Run");
return true;
}
}
// 4. 检查Office 365部署配置
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\15.0\\ClickToRun"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\15.0\\ClickToRun"))
{
if (key != null)
{
LogHelper.WriteLogToFile("检测到Office 365 (15.0)", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到Office 365 (15.0)");
return true;
}
}
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\16.0\\ClickToRun"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\16.0\\ClickToRun"))
{
if (key != null)
{
LogHelper.WriteLogToFile("检测到Office 365 (16.0)", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到Office 365 (16.0)");
return true;
}
}
// 5. 检查Office 365零售订阅信息
using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\ClickToRun\\Configuration"))
using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Office\\ClickToRun\\Configuration"))
{
if (key != null)
{
LogHelper.WriteLogToFile("检测到Office 365配置", LogHelper.LogType.Info);
LogHelper.WriteLogToFile("检测到Office 365配置");
return true;
}
}
@@ -409,7 +844,7 @@ namespace Ink_Canvas
return false;
}
}
/// <summary>
/// 显示权限不足的错误提示
/// </summary>
@@ -417,7 +852,7 @@ namespace Ink_Canvas
{
const string message = "需要管理员权限才能完成此操作\n请以管理员身份重新启动应用程序";
LogHelper.WriteLogToFile(message, LogHelper.LogType.Error);
System.Windows.MessageBox.Show(message, "权限错误", MessageBoxButton.OK, MessageBoxImage.Error);
MessageBox.Show(message, "权限错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
/// <summary>
@@ -563,7 +998,7 @@ namespace Ink_Canvas
{
var platformVersion = key.GetValue("Platform") as string;
var clickToRunVersion = key.GetValue("VersionToReport") as string;
if (!string.IsNullOrEmpty(platformVersion))
{
var majorVersion = platformVersion.Split('.').FirstOrDefault();
@@ -623,13 +1058,13 @@ namespace Ink_Canvas
// 检查Office 365 Outlook和PowerPoint的特定路径
string[] apps = { "outlook", "powerpoint" };
foreach (var app in apps)
{
// 检查用户级别的注册表
string regPath = $"Software\\Microsoft\\Office\\16.0\\{app}\\Security";
LogHelper.WriteLogToFile($"检查Office 365特定应用注册表: {regPath}");
try
{
// 先检查是否存在该路径
@@ -640,14 +1075,14 @@ namespace Ink_Canvas
{
string backupFile = Path.Combine(backupPath, $"SecurityBackup_365_{app}_{DateTime.Now:yyyyMMddHHmmss}.reg");
LogHelper.WriteLogToFile($"创建Office 365 {app}备份文件: {backupFile}");
// 使用UTF8编码写入注册表文件
using (StreamWriter sw = new StreamWriter(backupFile, false, System.Text.Encoding.UTF8))
using (StreamWriter sw = new StreamWriter(backupFile, false, Encoding.UTF8))
{
sw.WriteLine("Windows Registry Editor Version 5.00\n");
sw.WriteLine();
sw.WriteLine($"[{Microsoft.Win32.Registry.CurrentUser.Name}\\{regPath}]");
sw.WriteLine($"[{Registry.CurrentUser.Name}\\{regPath}]");
foreach (string valueName in baseKey.GetValueNames())
{
object value = baseKey.GetValue(valueName);
@@ -681,11 +1116,11 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"修改 {app} 注册表时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
// 尝试通过Office信任中心路径修改
string trustCenterPath = "Software\\Microsoft\\Office\\16.0\\Common\\Security\\FileValidation";
LogHelper.WriteLogToFile($"检查信任中心路径: {trustCenterPath}");
try
{
// 先检查是否存在该路径
@@ -696,14 +1131,14 @@ namespace Ink_Canvas
{
string backupFile = Path.Combine(backupPath, $"SecurityBackup_365_TrustCenter_{DateTime.Now:yyyyMMddHHmmss}.reg");
LogHelper.WriteLogToFile($"创建信任中心备份文件: {backupFile}");
// 使用UTF8编码写入注册表文件
using (StreamWriter sw = new StreamWriter(backupFile, false, System.Text.Encoding.UTF8))
using (StreamWriter sw = new StreamWriter(backupFile, false, Encoding.UTF8))
{
sw.WriteLine("Windows Registry Editor Version 5.00\n");
sw.WriteLine();
sw.WriteLine($"[{Microsoft.Win32.Registry.CurrentUser.Name}\\{trustCenterPath}]");
sw.WriteLine($"[{Registry.CurrentUser.Name}\\{trustCenterPath}]");
foreach (string valueName in baseKey.GetValueNames())
{
object value = baseKey.GetValue(valueName);
@@ -727,7 +1162,7 @@ namespace Ink_Canvas
{
LogHelper.WriteLogToFile($"修改信任中心路径时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 尝试修改EnableEditWhileViewingPolicy
string policyPath = "Software\\Policies\\Microsoft\\Office\\16.0\\Common\\Security";
try
@@ -740,14 +1175,14 @@ namespace Ink_Canvas
{
string backupFile = Path.Combine(backupPath, $"SecurityBackup_365_Policy_{DateTime.Now:yyyyMMddHHmmss}.reg");
LogHelper.WriteLogToFile($"创建策略备份文件: {backupFile}");
// 使用UTF8编码写入注册表文件
using (StreamWriter sw = new StreamWriter(backupFile, false, System.Text.Encoding.UTF8))
using (StreamWriter sw = new StreamWriter(backupFile, false, Encoding.UTF8))
{
sw.WriteLine("Windows Registry Editor Version 5.00\n");
sw.WriteLine();
sw.WriteLine($"[{Microsoft.Win32.Registry.CurrentUser.Name}\\{policyPath}]");
sw.WriteLine($"[{Registry.CurrentUser.Name}\\{policyPath}]");
foreach (string valueName in baseKey.GetValueNames())
{
object value = baseKey.GetValue(valueName);
+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("1.6.5")]
[assembly: AssemblyFileVersion("1.6.5")]
[assembly: AssemblyVersion("1.7.7.5")]
[assembly: AssemblyFileVersion("1.7.7.5")]
+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>
@@ -0,0 +1,562 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 异步硬件加速的墨迹平滑处理器
/// </summary>
public class AsyncAdvancedBezierSmoothing
{
private readonly SemaphoreSlim _processingSemaphore;
private readonly ConcurrentDictionary<Stroke, CancellationTokenSource> _processingTasks;
private readonly Dispatcher _uiDispatcher;
public AsyncAdvancedBezierSmoothing(Dispatcher uiDispatcher)
{
_uiDispatcher = uiDispatcher;
_processingSemaphore = new SemaphoreSlim(Environment.ProcessorCount, Environment.ProcessorCount);
_processingTasks = new ConcurrentDictionary<Stroke, CancellationTokenSource>();
}
public double SmoothingStrength { get; set; } = 0.3; // 大幅降低强度
public double ResampleInterval { get; set; } = 3.0; // 大幅增加间隔减少点数
public int InterpolationSteps { get; set; } = 8; // 从4增加到8,提高插值步数
public bool UseHardwareAcceleration { get; set; } = true;
public int MaxConcurrentTasks { get; set; } = Environment.ProcessorCount;
/// <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;
// 取消之前对同一笔画的处理
if (_processingTasks.TryGetValue(originalStroke, out var existingCts))
{
existingCts.Cancel();
_processingTasks.TryRemove(originalStroke, out _);
}
var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_processingTasks[originalStroke] = cts;
try
{
await _processingSemaphore.WaitAsync(cts.Token);
var smoothedStroke = await Task.Run(() =>
ProcessStrokeInternal(originalStroke, cts.Token), cts.Token);
// 在UI线程上执行回调
if (onCompleted != null && !cts.Token.IsCancellationRequested)
{
await _uiDispatcher.InvokeAsync(() => onCompleted(originalStroke, smoothedStroke));
}
return smoothedStroke;
}
catch (OperationCanceledException)
{
return originalStroke;
}
finally
{
_processingSemaphore.Release();
_processingTasks.TryRemove(originalStroke, out _);
cts.Dispose();
}
}
private Stroke ProcessStrokeInternal(Stroke stroke, CancellationToken cancellationToken)
{
var originalPoints = stroke.StylusPoints.ToArray();
// 如果点数太少,直接返回原始笔画
if (originalPoints.Length < 3)
return stroke;
cancellationToken.ThrowIfCancellationRequested();
// 简化处理:只进行轻度平滑,避免点数爆炸
var smoothedPoints = ApplyLightSmoothing(originalPoints);
cancellationToken.ThrowIfCancellationRequested();
// 确保点数不会过多
if (smoothedPoints.Length > originalPoints.Length * 2)
{
// 如果点数增加太多,回退到原始笔画
return stroke;
}
// 创建平滑后的笔画
var smoothedStroke = new Stroke(new StylusPointCollection(smoothedPoints))
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
return smoothedStroke;
}
/// <summary>
/// 轻度平滑处理,避免点数爆炸
/// </summary>
private StylusPoint[] ApplyLightSmoothing(StylusPoint[] points)
{
if (points.Length < 3) return points;
var result = new List<StylusPoint>();
result.Add(points[0]); // 保持第一个点
// 简单的3点平均平滑
for (int i = 1; i < points.Length - 1; i++)
{
var prev = points[i - 1];
var curr = points[i];
var next = points[i + 1];
// 3点平均
double x = (prev.X + curr.X + next.X) / 3.0;
double y = (prev.Y + curr.Y + next.Y) / 3.0;
float pressure = (prev.PressureFactor + curr.PressureFactor + next.PressureFactor) / 3.0f;
result.Add(new StylusPoint(x, y, Math.Max(pressure, 0.1f)));
}
result.Add(points[points.Length - 1]); // 保持最后一个点
return result.ToArray();
}
/// <summary>
/// 硬件加速的向量化指数平滑
/// </summary>
private StylusPoint[] ApplyExponentialSmoothingVectorized(StylusPoint[] points, double alpha)
{
if (points.Length == 0) return points;
var result = new StylusPoint[points.Length];
result[0] = points[0];
double lastX = points[0].X;
double lastY = points[0].Y;
float lastPressure = points[0].PressureFactor;
double oneMinusAlpha = 1.0 - alpha;
// 向量化处理,减少分支预测失败
for (int i = 1; i < points.Length; i++)
{
var p = points[i];
lastX = alpha * p.X + oneMinusAlpha * lastX;
lastY = alpha * p.Y + oneMinusAlpha * lastY;
lastPressure = (float)(alpha * p.PressureFactor + oneMinusAlpha * lastPressure);
lastPressure = Math.Max(lastPressure, 0.1f); // 避免分支
result[i] = new StylusPoint(lastX, lastY, lastPressure);
}
return result;
}
/// <summary>
/// 优化的等距重采样
/// </summary>
private StylusPoint[] ResampleEquidistantOptimized(StylusPoint[] points, double interval)
{
if (points.Length == 0) return points;
var result = new List<StylusPoint>(points.Length) { 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();
}
/// <summary>
/// 硬件加速的贝塞尔曲线拟合
/// </summary>
private StylusPoint[] SlidingBezierFitHardwareAccelerated(StylusPoint[] points, int window, int steps)
{
if (points.Length < window) return points;
var result = new List<StylusPoint>(points.Length * steps / window);
// 使用并行处理加速计算
var segments = new List<StylusPoint[]>();
Parallel.For(0, points.Length - window + 1, i =>
{
var segmentPoints = new StylusPoint[steps];
var p0 = points[i];
var p1 = points[i + 1];
var p2 = points[i + 2];
var p3 = points[i + 3];
for (int j = 0; j < steps; j++)
{
double t = (double)j / steps;
segmentPoints[j] = CubicBezierOptimized(p0, p1, p2, p3, t);
}
lock (segments)
{
segments.Add(segmentPoints);
}
});
// 合并结果
foreach (var segment in segments)
{
result.AddRange(segment);
}
result.Add(points[points.Length - 1]);
return result.ToArray();
}
/// <summary>
/// 优化的单线程贝塞尔拟合
/// </summary>
private StylusPoint[] SlidingBezierFitOptimized(StylusPoint[] points, int window, int steps)
{
if (points.Length < window) return points;
var result = new List<StylusPoint>(points.Length * steps / window);
for (int i = 0; i <= points.Length - window; i++)
{
var p0 = points[i];
var p1 = points[i + 1];
var p2 = points[i + 2];
var p3 = points[i + 3];
for (int j = 0; j < steps; j++)
{
double t = (double)j / steps;
result.Add(CubicBezierOptimized(p0, p1, p2, p3, t));
}
}
result.Add(points[points.Length - 1]);
return result.ToArray();
}
/// <summary>
/// 优化的三次贝塞尔曲线计算
/// </summary>
private StylusPoint CubicBezierOptimized(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 c0 = uuu;
double c1 = 3 * uu * t;
double c2 = 3 * u * tt;
double c3 = ttt;
double x = c0 * p0.X + c1 * p1.X + c2 * p2.X + c3 * p3.X;
double y = c0 * p0.Y + c1 * p1.Y + c2 * p2.Y + c3 * p3.Y;
float pressure = (float)(p1.PressureFactor * u + p2.PressureFactor * t);
pressure = Math.Max(pressure, 0.1f);
return new StylusPoint(x, y, pressure);
}
/// <summary>
/// 兼容性方法:传统指数平滑
/// </summary>
private StylusPoint[] ApplyExponentialSmoothing(StylusPoint[] points, double alpha)
{
if (points.Length == 0) return points;
var result = new StylusPoint[points.Length];
result[0] = points[0];
double lastX = points[0].X;
double lastY = points[0].Y;
float lastPressure = points[0].PressureFactor;
for (int i = 1; i < points.Length; i++)
{
var p = points[i];
lastX = alpha * p.X + (1 - alpha) * lastX;
lastY = alpha * p.Y + (1 - alpha) * lastY;
lastPressure = (float)(alpha * p.PressureFactor + (1 - alpha) * lastPressure);
lastPressure = Math.Max(lastPressure, 0.1f);
result[i] = new StylusPoint(lastX, lastY, lastPressure);
}
return result;
}
/// <summary>
/// 取消所有正在进行的处理任务
/// </summary>
public void CancelAllTasks()
{
foreach (var kvp in _processingTasks)
{
kvp.Value.Cancel();
}
_processingTasks.Clear();
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
CancelAllTasks();
_processingSemaphore?.Dispose();
}
}
/// <summary>
/// 原有的同步版本(保持向后兼容)
/// </summary>
public class AdvancedBezierSmoothing
{
public double SmoothingStrength { get; set; } = 0.3;
public double ResampleInterval { get; set; } = 3.0;
public int InterpolationSteps { get; set; } = 8;
public Stroke SmoothStroke(Stroke stroke)
{
if (stroke == null || stroke.StylusPoints.Count < 3)
return stroke;
var originalPoints = stroke.StylusPoints.ToList();
// 简化处理:只进行轻度平滑
var smoothedPoints = ApplyLightExponentialSmoothing(originalPoints, 0.2); // 很轻的平滑
// 检查点数是否合理
if (smoothedPoints.Count > originalPoints.Count * 1.5)
{
return stroke; // 如果点数增加太多,返回原始笔画
}
var smoothedStroke = new Stroke(new StylusPointCollection(smoothedPoints))
{
DrawingAttributes = stroke.DrawingAttributes.Clone()
};
return smoothedStroke;
}
/// <summary>
/// 轻度指数平滑
/// </summary>
private List<StylusPoint> ApplyLightExponentialSmoothing(List<StylusPoint> points, double alpha)
{
var result = new List<StylusPoint>();
if (points.Count == 0) return result;
result.Add(points[0]);
for (int i = 1; i < points.Count; i++)
{
var prev = result[result.Count - 1];
var curr = points[i];
double x = alpha * curr.X + (1 - alpha) * prev.X;
double y = alpha * curr.Y + (1 - alpha) * prev.Y;
float pressure = (float)(alpha * curr.PressureFactor + (1 - alpha) * prev.PressureFactor);
pressure = Math.Max(pressure, 0.1f);
result.Add(new StylusPoint(x, y, pressure));
}
return result;
}
private List<StylusPoint> ApplyExponentialSmoothing(List<StylusPoint> points, double alpha)
{
var result = new List<StylusPoint>();
if (points.Count == 0) return result;
result.Add(points[0]);
double lastX = points[0].X;
double lastY = points[0].Y;
float lastPressure = points[0].PressureFactor;
for (int i = 1; i < points.Count; i++)
{
var p = points[i];
lastX = alpha * p.X + (1 - alpha) * lastX;
lastY = alpha * p.Y + (1 - alpha) * lastY;
lastPressure = (float)(alpha * p.PressureFactor + (1 - alpha) * lastPressure);
if (lastPressure < 0.1f) lastPressure = 0.1f;
result.Add(new StylusPoint(lastX, lastY, lastPressure));
}
return result;
}
private List<StylusPoint> ResampleEquidistant(List<StylusPoint> points, double interval = 2.0)
{
var result = new List<StylusPoint>();
if (points.Count == 0) return result;
result.Add(points[0]);
double accumulated = 0;
for (int i = 1; i < points.Count; i++)
{
var prev = result.Last();
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);
if (pressure < 0.1f) pressure = 0.1f;
var newPoint = new StylusPoint(x, y, pressure);
result.Add(newPoint);
accumulated = 0;
i--; // 重新处理当前点
}
else
{
accumulated += dist;
}
}
return result;
}
private List<StylusPoint> SlidingBezierFit(List<StylusPoint> points, int window = 4, int steps = 48) // 从24增加到48
{
var result = new List<StylusPoint>();
if (points.Count < window) return points;
for (int i = 0; i <= points.Count - window; i++)
{
var p0 = points[i];
var p1 = points[i + 1];
var p2 = points[i + 2];
var p3 = points[i + 3];
for (int j = 0; j < steps; j++)
{
double t = (double)j / steps;
var pt = CubicBezier(p0, p1, p2, p3, t);
result.Add(pt);
}
}
// 保证最后一个点被包含
result.Add(points.Last());
return result;
}
private StylusPoint CubicBezier(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 * (1 - t) + p2.PressureFactor * t);
if (pressure < 0.1f) pressure = 0.1f;
return new StylusPoint(x, y, pressure);
}
private List<StylusPoint> SlidingWindowSmooth(List<StylusPoint> points, int window = 5)
{
var result = new List<StylusPoint>();
int half = window / 2;
for (int i = 0; i < points.Count; i++)
{
double sumX = 0, sumY = 0, sumP = 0;
int count = 0;
for (int j = Math.Max(0, i - half); j <= Math.Min(points.Count - 1, i + half); j++)
{
sumX += points[j].X;
sumY += points[j].Y;
sumP += points[j].PressureFactor;
count++;
}
result.Add(new StylusPoint(sumX / count, sumY / count, (float)(sumP / count)));
}
return result;
}
}
/// <summary>
/// 性能监控器
/// </summary>
public class InkSmoothingPerformanceMonitor
{
private readonly Queue<TimeSpan> _processingTimes = new Queue<TimeSpan>();
private readonly object _lock = new object();
private const int MaxSamples = 100;
public void RecordProcessingTime(TimeSpan time)
{
lock (_lock)
{
_processingTimes.Enqueue(time);
if (_processingTimes.Count > MaxSamples)
_processingTimes.Dequeue();
}
}
public double GetAverageProcessingTimeMs()
{
lock (_lock)
{
return _processingTimes.Count > 0 ?
_processingTimes.Average(t => t.TotalMilliseconds) : 0;
}
}
public double GetMaxProcessingTimeMs()
{
lock (_lock)
{
return _processingTimes.Count > 0 ?
_processingTimes.Max(t => t.TotalMilliseconds) : 0;
}
}
public int GetSampleCount()
{
lock (_lock)
{
return _processingTimes.Count;
}
}
}
}
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;
}
}
+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)]
+26 -110
View File
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace Ink_Canvas.Helpers
{
@@ -23,46 +24,9 @@ namespace Ink_Canvas.Helpers
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("shell32.dll")]
private static extern IntPtr SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);
[DllImport("user32.dll")]
private static extern int SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
[DllImport("user32.dll")]
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
[DllImport("user32.dll")]
private static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
private const uint ABM_GETTASKBARPOS = 0x00000005;
private const uint ABM_GETSTATE = 0x00000004;
private const int SPI_GETWORKAREA = 0x0030;
private const uint MONITOR_DEFAULTTOPRIMARY = 1;
private const int ABS_AUTOHIDE = 0x0000001;
[StructLayout(LayoutKind.Sequential)]
private struct MONITORINFO
public struct RECT
{
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public uint uEdge;
public RECT rc;
public IntPtr lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
@@ -72,73 +36,8 @@ namespace Ink_Canvas.Helpers
public int Height => Bottom - Top;
}
/// <summary>
/// 获取Windows任务栏的高度(仅计算任务栏,不包括其他应用的停靠栏)
/// </summary>
/// <param name="screen">当前屏幕</param>
/// <param name="dpiScaleY">DPI缩放Y值</param>
/// <returns>任务栏高度</returns>
public static double GetTaskbarHeight(System.Windows.Forms.Screen screen, double dpiScaleY)
public static string WindowTitle()
{
try
{
// 创建APPBARDATA结构
var abd = new APPBARDATA();
abd.cbSize = Marshal.SizeOf(abd);
// 获取任务栏状态
IntPtr state = SHAppBarMessage(ABM_GETSTATE, ref abd);
bool isAutoHide = (state.ToInt32() & ABS_AUTOHIDE) == ABS_AUTOHIDE;
// 如果任务栏是自动隐藏的,返回0
if (isAutoHide)
{
LogHelper.WriteLogToFile("任务栏处于自动隐藏状态", LogHelper.LogType.Info);
return 0;
}
// 获取任务栏信息
IntPtr result = SHAppBarMessage(ABM_GETTASKBARPOS, ref abd);
if (result != IntPtr.Zero)
{
// 获取当前屏幕的工作区
RECT workArea = new RECT();
SystemParametersInfo(SPI_GETWORKAREA, 0, Marshal.AllocHGlobal(Marshal.SizeOf(workArea)), 0);
// 根据任务栏位置计算高度
int taskbarHeight = 0;
// 任务栏的uEdge: 0=左, 1=上, 2=右, 3=下
switch (abd.uEdge)
{
case 1: // 上
taskbarHeight = abd.rc.Height;
break;
case 3: // 下
taskbarHeight = abd.rc.Height;
break;
case 0: // 左
case 2: // 右
// 水平任务栏不影响高度
taskbarHeight = 0;
break;
}
// 考虑DPI缩放
return taskbarHeight / dpiScaleY;
}
}
catch (Exception ex)
{
Debug.WriteLine($"获取任务栏高度出错: {ex.Message}");
LogHelper.WriteLogToFile($"获取任务栏高度出错: {ex.Message}", LogHelper.LogType.Error);
}
// 如果获取失败,回退到通用方法
return (screen.Bounds.Height - screen.WorkingArea.Height) / dpiScaleY;
}
public static string WindowTitle() {
IntPtr foregroundWindowHandle = GetForegroundWindow();
const int nChars = 256;
@@ -148,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;
@@ -158,7 +58,8 @@ namespace Ink_Canvas.Helpers
return className.ToString();
}
public static RECT WindowRect() {
public static RECT WindowRect()
{
IntPtr foregroundWindowHandle = GetForegroundWindow();
RECT windowRect;
@@ -167,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";
}
@@ -192,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...... 你信么
}
//将修改后的结构体拷贝回去
@@ -0,0 +1,257 @@
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 readonly DrawingContext _drawingContext;
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()
{
_drawingContext?.Close();
_renderTarget?.Clear();
_isInitialized = false;
}
}
/// <summary>
/// 质量配置枚举
/// </summary>
public enum InkSmoothingQuality
{
HighPerformance = 0, // 高性能低质量
Balanced = 1, // 平衡
HighQuality = 2 // 高质量低性能
}
/// <summary>
/// 墨迹平滑配置
/// </summary>
public class InkSmoothingConfig
{
public InkSmoothingQuality Quality { get; set; } = InkSmoothingQuality.HighQuality;
public bool UseHardwareAcceleration { get; set; } = true;
public bool UseAsyncProcessing { get; set; } = true;
public int MaxConcurrentTasks { get; set; } = Environment.ProcessorCount;
public double SmoothingStrength { get; set; } = 0.8; // 高质量模式的平滑强度
public double ResampleInterval { get; set; } = 0.8; // 高质量模式的重采样间隔
public int InterpolationSteps { get; set; } = 64; // 高质量模式的插值步数
public static InkSmoothingConfig FromSettings()
{
return new InkSmoothingConfig
{
Quality = (InkSmoothingQuality)MainWindow.Settings.Canvas.InkSmoothingQuality,
UseHardwareAcceleration = MainWindow.Settings.Canvas.UseHardwareAcceleration,
UseAsyncProcessing = MainWindow.Settings.Canvas.UseAsyncInkSmoothing,
MaxConcurrentTasks = MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks > 0 ?
MainWindow.Settings.Canvas.MaxConcurrentSmoothingTasks : Environment.ProcessorCount
};
}
public void ApplyQualitySettings()
{
switch (Quality)
{
case InkSmoothingQuality.HighPerformance:
SmoothingStrength = 0.4;
ResampleInterval = 2.0;
InterpolationSteps = 16;
break;
case InkSmoothingQuality.Balanced:
SmoothingStrength = 0.6;
ResampleInterval = 1.2;
InterpolationSteps = 32;
break;
case InkSmoothingQuality.HighQuality:
SmoothingStrength = 0.8;
ResampleInterval = 0.8;
InterpolationSteps = 64;
break;
}
}
}
}
+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);
}
}
}
}
+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;
+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 = InkSmoothingQuality.HighQuality;
config.UseHardwareAcceleration = true;
config.UseAsyncProcessing = true;
config.MaxConcurrentTasks = Math.Min(processorCount, 8);
}
else if (processorCount >= 2)
{
// 2核以上使用平衡模式
config.Quality = InkSmoothingQuality.Balanced;
config.UseHardwareAcceleration = isHardwareAccelerated;
config.UseAsyncProcessing = true;
config.MaxConcurrentTasks = Math.Min(processorCount, 4);
}
else
{
// 单核或性能较低的设备使用高性能模式
config.Quality = 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);
+1 -1
View File
@@ -32,7 +32,7 @@ namespace Ink_Canvas.Helpers
/// <summary>
/// 创建显示笔迹的类
/// </summary>
public StrokeVisual() : this(new DrawingAttributes()
public StrokeVisual() : this(new DrawingAttributes
{
Color = Colors.Red,
//FitToCurve = true,
+395
View File
@@ -0,0 +1,395 @@
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.IO;
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 = false;
// 墨迹锁定机制,防止翻页时的墨迹冲突
private DateTime _inkLockUntil = DateTime.MinValue;
private int _lockedSlideIndex = -1;
private const int InkLockMilliseconds = 500;
#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
{
// 生成演示文稿唯一标识符
_currentPresentationId = GeneratePresentationId(presentation);
// 重新初始化内存流数组
var slideCount = presentation.Slides.Count;
_memoryStreams = new MemoryStream[slideCount + 2];
// 如果启用自动保存,尝试加载已保存的墨迹
if (IsAutoSaveEnabled && !string.IsNullOrEmpty(AutoSaveLocation))
{
LoadSavedStrokes();
}
LogHelper.WriteLogToFile($"已初始化演示文稿墨迹管理: {presentation.Name}, 幻灯片数量: {slideCount}", LogHelper.LogType.Trace);
}
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))
{
LogHelper.WriteLogToFile($"墨迹写入被锁定,当前页:{slideIndex},锁定页:{_lockedSlideIndex}", LogHelper.LogType.Warning);
return;
}
if (slideIndex < _memoryStreams.Length)
{
var ms = new MemoryStream();
strokes.Save(ms);
ms.Position = 0;
// 释放旧的内存流
_memoryStreams[slideIndex]?.Dispose();
_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]);
LogHelper.WriteLogToFile($"已加载第{slideIndex}页墨迹,笔画数量: {strokes.Count}", LogHelper.LogType.Trace);
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
{
// 如果有当前墨迹,先保存
if (currentStrokes != null && currentStrokes.Count > 0)
{
SaveCurrentSlideStrokes(_lockedSlideIndex > 0 ? _lockedSlideIndex : slideIndex, currentStrokes);
}
// 设置墨迹锁定
LockInkForSlide(slideIndex);
// 加载新页面的墨迹
return LoadSlideStrokes(slideIndex);
}
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;
for (int i = 1; i <= presentation.Slides.Count && 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++;
LogHelper.WriteLogToFile($"已保存第{i}页墨迹,大小: {byteLength} bytes", LogHelper.LogType.Trace);
}
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);
}
}
}
LogHelper.WriteLogToFile($"已保存{savedCount}页墨迹到文件", LogHelper.LogType.Event);
}
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);
}
}
LogHelper.WriteLogToFile($"已从文件加载{loadedCount}页墨迹", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从文件加载墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
}
/// <summary>
/// 清除所有墨迹
/// </summary>
public void ClearAllStrokes()
{
lock (_lockObject)
{
try
{
for (int i = 0; i < _memoryStreams.Length; i++)
{
_memoryStreams[i]?.Dispose();
_memoryStreams[i] = null;
}
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 false;
if (currentSlideIndex != _lockedSlideIndex && _lockedSlideIndex > 0) return false;
return true;
}
#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
+435
View File
@@ -0,0 +1,435 @@
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 bool EnablePPTButtonPageClickable { 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}";
}
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
{
_mainWindow.PPTBtnPageNow.Text = currentSlide.ToString();
_mainWindow.PPTBtnPageTotal.Text = $"/ {totalSlides}";
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新页码显示失败: {ex}", LogHelper.LogType.Error);
}
});
}
/// <summary>
/// 更新导航面板显示状态
/// </summary>
public void UpdateNavigationPanelsVisibility()
{
_dispatcher.InvokeAsync(() =>
{
try
{
// 检查是否应该显示PPT按钮
bool shouldShowButtons = ShowPPTButton && _mainWindow.BtnPPTSlideShowEnd.Visibility == Visibility.Visible;
if (!shouldShowButtons)
{
HideAllNavigationPanels();
return;
}
// 设置侧边按钮位置
_mainWindow.LeftSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTLSButtonPosition * 2);
_mainWindow.RightSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTRSButtonPosition * 2);
// 根据显示选项设置面板可见性
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,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
}
}
+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();
}
}
+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);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -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;
}
}
}
+4 -6
View File
@@ -1,6 +1,7 @@
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Ink_Canvas.Helpers
@@ -27,10 +28,7 @@ namespace Ink_Canvas.Helpers
//MessageBox.Show("启动失败: " + ex.Message);
}
}
else
{
//Console.WriteLine(softwareName + " 未找到可执行文件路径。");
}
//Console.WriteLine(softwareName + " 未找到可执行文件路径。");
}
private static string FindEasiCameraExecutablePath(string softwareName)
@@ -51,7 +49,7 @@ namespace Ink_Canvas.Helpers
{
if (!string.IsNullOrEmpty(installLocation))
{
executablePath = System.IO.Path.Combine(installLocation, "sweclauncher.exe");
executablePath = Path.Combine(installLocation, "sweclauncher.exe");
}
else if (!string.IsNullOrEmpty(uninstallString))
{
@@ -59,7 +57,7 @@ namespace Ink_Canvas.Helpers
if (lastSlashIndex >= 0)
{
string folderPath = uninstallString.Substring(0, lastSlashIndex);
executablePath = System.IO.Path.Combine(folderPath, "sweclauncher", "sweclauncher.exe");
executablePath = Path.Combine(folderPath, "sweclauncher", "sweclauncher.exe");
}
}
break;
+51
View File
@@ -0,0 +1,51 @@
using System.IO;
namespace Ink_Canvas.Helpers
{
public static class StartupCount
{
private static readonly string CountFilePath = Path.Combine(App.RootPath, "startup-count");
private static readonly object fileLock = new object();
public static int GetCount()
{
try
{
if (File.Exists(CountFilePath))
{
var text = File.ReadAllText(CountFilePath).Trim();
if (int.TryParse(text, out int count))
return count;
}
}
catch { }
return 0;
}
public static void Increment()
{
lock (fileLock)
{
int count = GetCount() + 1;
try
{
File.WriteAllText(CountFilePath, count.ToString());
}
catch { }
}
}
public static void Reset()
{
lock (fileLock)
{
try
{
if (File.Exists(CountFilePath))
File.Delete(CountFilePath);
}
catch { }
}
}
}
}
+40 -4
View File
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
// Added for UIElement
namespace Ink_Canvas.Helpers
{
public class TimeMachine
public partial class TimeMachine
{
private readonly List<TimeMachineHistory> _currentStrokeHistory = new List<TimeMachineHistory>();
@@ -133,12 +135,13 @@ namespace Ink_Canvas.Helpers
public class TimeMachineHistory
{
public TimeMachineHistoryType CommitType;
public bool StrokeHasBeenCleared = false;
public bool StrokeHasBeenCleared;
public StrokeCollection CurrentStroke;
public StrokeCollection ReplacedStroke;
//这里说一下 Tuple的 Value1 是初始值 ; Value 2 是改变值
public Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> StylusPointDictionary;
public Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> DrawingAttributes;
public UIElement InsertedElement; // 新增
public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared)
{
CommitType = commitType;
@@ -163,6 +166,11 @@ namespace Ink_Canvas.Helpers
StrokeHasBeenCleared = strokeHasBeenCleared;
ReplacedStroke = replacedStroke;
}
public TimeMachineHistory(UIElement element, TimeMachineHistoryType commitType) // 新增
{
CommitType = commitType;
InsertedElement = element;
}
}
public enum TimeMachineHistoryType
@@ -171,6 +179,34 @@ namespace Ink_Canvas.Helpers
ShapeRecognition,
Clear,
Manipulation,
DrawingAttributes
DrawingAttributes,
ElementInsert // 新增
}
public partial class TimeMachine // 新增partial,便于扩展
{
public void CommitElementInsertHistory(UIElement element)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
_currentStrokeHistory.Add(new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert));
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
public void CommitElementRemoveHistory(UIElement element)
{
if (_currentIndex + 1 < _currentStrokeHistory.Count)
{
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
}
var history = new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert);
history.StrokeHasBeenCleared = true; // 标记为已清除
_currentStrokeHistory.Add(history);
_currentIndex = _currentStrokeHistory.Count - 1;
NotifyUndoRedoState();
}
}
}
+21 -10
View File
@@ -1,7 +1,9 @@
using System.Windows.Automation;
namespace Ink_Canvas.Helpers {
internal class WinTabWindowsChecker {
namespace Ink_Canvas.Helpers
{
internal class WinTabWindowsChecker
{
/*
public static bool IsWindowMinimized(string windowName, bool matchFullName = true) {
// 获取Win+Tab预览中的窗口
@@ -40,28 +42,37 @@ namespace Ink_Canvas.Helpers {
}
*/
public static bool IsWindowExisted(string windowName, bool matchFullName = true) {
public static bool IsWindowExisted(string windowName, bool matchFullName = true)
{
// 获取Win+Tab预览中的窗口
AutomationElementCollection windows = AutomationElement.RootElement.FindAll(
TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
foreach (AutomationElement window in windows) {
foreach (AutomationElement window in windows)
{
//LogHelper.WriteLogToFile("" + window.Current.Name);
string windowTitle = window.Current.Name;
// 如果窗口标题包含 windowName,则进行检查
if (!string.IsNullOrEmpty(windowTitle) && windowTitle.Contains(windowName)) {
if (matchFullName) {
if (windowTitle.Length == windowName.Length) {
if (!string.IsNullOrEmpty(windowTitle) && windowTitle.Contains(windowName))
{
if (matchFullName)
{
if (windowTitle.Length == windowName.Length)
{
WindowPattern windowPattern = window.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
if (windowPattern != null) {
if (windowPattern != null)
{
return true;
}
}
} else {
}
else
{
WindowPattern windowPattern = window.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
if (windowPattern != null) {
if (windowPattern != null)
{
return true;
}
}
+14
View File
@@ -113,12 +113,15 @@
<ItemGroup>
<Reference Include="IACore">
<HintPath>.\IACore.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="IALoader">
<HintPath>.\IALoader.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="IAWinFX">
<HintPath>.\IAWinFX.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="netstandard" />
@@ -132,12 +135,18 @@
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Costura.Fody" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.9.27" />
<PackageReference Include="MdXaml" Version="1.27.0" />
@@ -181,6 +190,11 @@
<ItemGroup>
<None Include="Resources\TimerDownNotice.wav" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\IACore\IACore.dll" />
<EmbeddedResource Include="Resources\IACore\IALoader.dll" />
<EmbeddedResource Include="Resources\IACore\IAWinFX.dll" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Cursors\Cursor.cur" />
<Resource Include="Resources\Cursors\Pen.cur" />
+1447 -230
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+96 -50
View File
@@ -1,7 +1,6 @@
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -9,14 +8,16 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Ink_Canvas {
public partial class MainWindow : Window {
public bool isFloatingBarFolded = false;
private bool isFloatingBarChangingHideMode = false;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
public bool isFloatingBarFolded;
private bool isFloatingBarChangingHideMode;
private void CloseWhiteboardImmediately() {
private void CloseWhiteboardImmediately()
{
if (isDisplayingOrHidingBlackboard) return;
isDisplayingOrHidingBlackboard = true;
HideSubPanelsImmediately();
@@ -30,21 +31,24 @@ namespace Ink_Canvas {
BtnSwitch_Click(BtnSwitch, null);
BtnExit.Foreground = Brushes.White;
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
new Thread(new ThreadStart(() => {
new Thread(() =>
{
Thread.Sleep(200);
Application.Current.Dispatcher.Invoke(() => { isDisplayingOrHidingBlackboard = false; });
})).Start();
}).Start();
}
public async void FoldFloatingBar_MouseUp(object sender, MouseButtonEventArgs e) {
public async void FoldFloatingBar_MouseUp(object sender, MouseButtonEventArgs e)
{
await FoldFloatingBar(sender);
}
public async Task FoldFloatingBar(object sender)
public async Task FoldFloatingBar(object sender, bool isAutoFoldCommand = false)
{
var isShouldRejectAction = false;
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
((Panel)lastBorderMouseDownObject).Background = new SolidColorBrush(Colors.Transparent);
if (sender == Fold_Icon && lastBorderMouseDownObject != Fold_Icon) isShouldRejectAction = true;
@@ -54,14 +58,15 @@ namespace Ink_Canvas {
// FloatingBarIcons_MouseUp_New(sender);
if (sender == null)
foldFloatingBarByUser = true;
foldFloatingBarByUser = false;
else
foldFloatingBarByUser = true;
unfoldFloatingBarByUser = false;
if (isFloatingBarChangingHideMode) return;
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
InkCanvasForInkReplay.Visibility = Visibility.Collapsed;
InkCanvasGridForInkReplay.Visibility = Visibility.Visible;
InkCanvasGridForInkReplay.IsHitTestVisible = true;
@@ -73,7 +78,8 @@ namespace Ink_Canvas {
isStopInkReplay = true;
});
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
isFloatingBarChangingHideMode = true;
isFloatingBarFolded = true;
if (currentMode != 0) CloseWhiteboardImmediately();
@@ -84,13 +90,15 @@ namespace Ink_Canvas {
CursorWithDelIcon_Click(sender, null);
});
await Task.Delay(10);
await Task.Delay(300);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
LeftBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
RightBottomPanelForPPTNavigation.Visibility = Visibility.Collapsed;
LeftSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
RightSidePanelForPPTNavigation.Visibility = Visibility.Collapsed;
GridForFloatingBarDraging.Visibility = Visibility.Collapsed;
ViewboxFloatingBarMarginAnimation(-60);
HideSubPanels("cursor");
SidePannelMarginAnimation(-10);
@@ -98,12 +106,16 @@ namespace Ink_Canvas {
isFloatingBarChangingHideMode = false;
}
private async void LeftUnFoldButtonDisplayQuickPanel_MouseUp(object sender, MouseButtonEventArgs e) {
if (Settings.Appearance.IsShowQuickPanel == true) {
private async void LeftUnFoldButtonDisplayQuickPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
if (Settings.Appearance.IsShowQuickPanel)
{
HideRightQuickPanel();
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Visible;
await Dispatcher.InvokeAsync(() => {
var marginAnimation = new ThicknessAnimation {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
From = new Thickness(-50, 0, 0, -150),
To = new Thickness(-1, 0, 0, -150)
@@ -113,21 +125,27 @@ namespace Ink_Canvas {
});
await Task.Delay(100);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
LeftUnFoldButtonQuickPanel.Margin = new Thickness(-1, 0, 0, -150);
});
}
else {
else
{
UnFoldFloatingBar_MouseUp(sender, e);
}
}
private async void RightUnFoldButtonDisplayQuickPanel_MouseUp(object sender, MouseButtonEventArgs e) {
if (Settings.Appearance.IsShowQuickPanel == true) {
private async void RightUnFoldButtonDisplayQuickPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
if (Settings.Appearance.IsShowQuickPanel)
{
HideLeftQuickPanel();
RightUnFoldButtonQuickPanel.Visibility = Visibility.Visible;
await Dispatcher.InvokeAsync(() => {
var marginAnimation = new ThicknessAnimation {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
From = new Thickness(0, 0, -50, -150),
To = new Thickness(0, 0, -1, -150)
@@ -137,19 +155,25 @@ namespace Ink_Canvas {
});
await Task.Delay(100);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
RightUnFoldButtonQuickPanel.Margin = new Thickness(0, 0, -1, -150);
});
}
else {
else
{
UnFoldFloatingBar_MouseUp(sender, e);
}
}
private async void HideLeftQuickPanel() {
if (LeftUnFoldButtonQuickPanel.Visibility == Visibility.Visible) {
await Dispatcher.InvokeAsync(() => {
var marginAnimation = new ThicknessAnimation {
private async void HideLeftQuickPanel()
{
if (LeftUnFoldButtonQuickPanel.Visibility == Visibility.Visible)
{
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
From = new Thickness(-1, 0, 0, -150),
To = new Thickness(-50, 0, 0, -150)
@@ -159,17 +183,22 @@ namespace Ink_Canvas {
});
await Task.Delay(100);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
LeftUnFoldButtonQuickPanel.Margin = new Thickness(0, 0, -50, -150);
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
});
}
}
private async void HideRightQuickPanel() {
if (RightUnFoldButtonQuickPanel.Visibility == Visibility.Visible) {
await Dispatcher.InvokeAsync(() => {
var marginAnimation = new ThicknessAnimation {
private async void HideRightQuickPanel()
{
if (RightUnFoldButtonQuickPanel.Visibility == Visibility.Visible)
{
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
From = new Thickness(0, 0, -1, -150),
To = new Thickness(0, 0, -50, -150)
@@ -179,25 +208,29 @@ namespace Ink_Canvas {
});
await Task.Delay(100);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
RightUnFoldButtonQuickPanel.Margin = new Thickness(0, 0, -50, -150);
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
});
}
}
private void HideQuickPanel_MouseUp(object sender, MouseButtonEventArgs e) {
private void HideQuickPanel_MouseUp(object sender, MouseButtonEventArgs e)
{
HideLeftQuickPanel();
HideRightQuickPanel();
}
public async void UnFoldFloatingBar_MouseUp(object sender, MouseButtonEventArgs e) {
public async void UnFoldFloatingBar_MouseUp(object sender, MouseButtonEventArgs e)
{
await UnFoldFloatingBar(sender);
}
public async Task UnFoldFloatingBar(object sender)
{
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
LeftUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
RightUnFoldButtonQuickPanel.Visibility = Visibility.Collapsed;
});
@@ -209,14 +242,23 @@ namespace Ink_Canvas {
if (isFloatingBarChangingHideMode) return;
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
isFloatingBarChangingHideMode = true;
isFloatingBarFolded = false;
});
await Task.Delay(0);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
// 根据设置决定是否自动切换至批注模式
if (Settings.Automation.IsAutoEnterAnnotationModeWhenExitFoldMode && currentMode == 0)
{
// 切换至批注模式
PenIcon_Click(null, null);
}
if (StackPanelPPTControls.Visibility == Visibility.Visible)
{
var dops = Settings.PowerPointSettings.PPTButtonsDisplayOption.ToString();
@@ -239,17 +281,20 @@ namespace Ink_Canvas {
private async void SidePannelMarginAnimation(int MarginFromEdge, bool isNoAnimation = false) // Possible value: -50, -10
{
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
if (MarginFromEdge == -10) LeftSidePanel.Visibility = Visibility.Visible;
var LeftSidePanelmarginAnimation = new ThicknessAnimation {
Duration = isNoAnimation == true ? TimeSpan.FromSeconds(0) : TimeSpan.FromSeconds(0.175),
var LeftSidePanelmarginAnimation = new ThicknessAnimation
{
Duration = isNoAnimation ? TimeSpan.FromSeconds(0) : TimeSpan.FromSeconds(0.175),
From = LeftSidePanel.Margin,
To = new Thickness(MarginFromEdge, 0, 0, -150)
};
LeftSidePanelmarginAnimation.EasingFunction = new CubicEase();
var RightSidePanelmarginAnimation = new ThicknessAnimation {
Duration = isNoAnimation == true ? TimeSpan.FromSeconds(0) : TimeSpan.FromSeconds(0.175),
var RightSidePanelmarginAnimation = new ThicknessAnimation
{
Duration = isNoAnimation ? TimeSpan.FromSeconds(0) : TimeSpan.FromSeconds(0.175),
From = RightSidePanel.Margin,
To = new Thickness(0, 0, MarginFromEdge, -150)
};
@@ -260,7 +305,8 @@ namespace Ink_Canvas {
await Task.Delay(600);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
LeftSidePanel.Margin = new Thickness(MarginFromEdge, 0, 0, -150);
RightSidePanel.Margin = new Thickness(0, 0, MarginFromEdge, -150);
+17 -9
View File
@@ -1,16 +1,22 @@
using IWshRuntimeLibrary;
using System;
using System.Windows;
using Application = System.Windows.Forms.Application;
using File = System.IO.File;
namespace Ink_Canvas {
public partial class MainWindow : Window {
public static bool StartAutomaticallyCreate(string exeName) {
try {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
public static bool StartAutomaticallyCreate(string exeName)
{
try
{
var shell = new WshShell();
var shortcut = (IWshShortcut)shell.CreateShortcut(
Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName + ".lnk");
//设置快捷方式的目标所在的位置(源程序完整路径)
shortcut.TargetPath = System.Windows.Forms.Application.ExecutablePath;
shortcut.TargetPath = Application.ExecutablePath;
//应用程序的工作目录
//当用户没有指定一个具体的目录时,快捷方式的目标应用程序将使用该属性所指定的目录来装载或保存文件。
shortcut.WorkingDirectory = Environment.CurrentDirectory;
@@ -28,10 +34,12 @@ namespace Ink_Canvas {
return false;
}
public static bool StartAutomaticallyDel(string exeName) {
try {
System.IO.File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName +
".lnk");
public static bool StartAutomaticallyDel(string exeName)
{
try
{
File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName +
".lnk");
return true;
}
catch (Exception) { }
+35 -26
View File
@@ -1,50 +1,55 @@
using Microsoft.Win32;
using iNKORE.UI.WPF.Modern;
using iNKORE.UI.WPF.Modern;
using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Media;
using Application = System.Windows.Application;
namespace Ink_Canvas {
public partial class MainWindow : Window {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private Color FloatBarForegroundColor = Color.FromRgb(102, 102, 102);
private void SetTheme(string theme) {
if (theme == "Light") {
var rd1 = new ResourceDictionary()
{ Source = new Uri("Resources/Styles/Light.xaml", UriKind.Relative) };
private void SetTheme(string theme)
{
if (theme == "Light")
{
var rd1 = new ResourceDictionary
{ Source = new Uri("Resources/Styles/Light.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd1);
var rd2 = new ResourceDictionary()
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
var rd2 = new ResourceDictionary
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd2);
var rd3 = new ResourceDictionary()
{ Source = new Uri("Resources/SeewoImageDictionary.xaml", UriKind.Relative) };
var rd3 = new ResourceDictionary
{ Source = new Uri("Resources/SeewoImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd3);
var rd4 = new ResourceDictionary()
{ Source = new Uri("Resources/IconImageDictionary.xaml", UriKind.Relative) };
var rd4 = new ResourceDictionary
{ Source = new Uri("Resources/IconImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd4);
ThemeManager.SetRequestedTheme(window, ElementTheme.Light);
FloatBarForegroundColor = (Color)Application.Current.FindResource("FloatBarForegroundColor");
}
else if (theme == "Dark") {
var rd1 = new ResourceDictionary() { Source = new Uri("Resources/Styles/Dark.xaml", UriKind.Relative) };
else if (theme == "Dark")
{
var rd1 = new ResourceDictionary { Source = new Uri("Resources/Styles/Dark.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd1);
var rd2 = new ResourceDictionary()
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
var rd2 = new ResourceDictionary
{ Source = new Uri("Resources/DrawShapeImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd2);
var rd3 = new ResourceDictionary()
{ Source = new Uri("Resources/SeewoImageDictionary.xaml", UriKind.Relative) };
var rd3 = new ResourceDictionary
{ Source = new Uri("Resources/SeewoImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd3);
var rd4 = new ResourceDictionary()
{ Source = new Uri("Resources/IconImageDictionary.xaml", UriKind.Relative) };
var rd4 = new ResourceDictionary
{ Source = new Uri("Resources/IconImageDictionary.xaml", UriKind.Relative) };
Application.Current.Resources.MergedDictionaries.Add(rd4);
ThemeManager.SetRequestedTheme(window, ElementTheme.Dark);
@@ -53,8 +58,10 @@ namespace Ink_Canvas {
}
}
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) {
switch (Settings.Appearance.Theme) {
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
switch (Settings.Appearance.Theme)
{
case 0:
SetTheme("Light");
break;
@@ -68,9 +75,11 @@ namespace Ink_Canvas {
}
}
private bool IsSystemThemeLight() {
private bool IsSystemThemeLight()
{
var light = false;
try {
try
{
var registryKey = Registry.CurrentUser;
var themeKey =
registryKey.OpenSubKey("software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize");
+184 -36
View File
@@ -1,20 +1,17 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
namespace Ink_Canvas {
public partial class MainWindow : Window {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private StrokeCollection[] strokeCollections = new StrokeCollection[101];
private bool[] whiteboadLastModeIsRedo = new bool[101];
private StrokeCollection lastTouchDownStrokeCollection = new StrokeCollection();
@@ -23,46 +20,167 @@ namespace Ink_Canvas {
private int WhiteboardTotalCount = 1;
private TimeMachineHistory[][] TimeMachineHistories = new TimeMachineHistory[101][]; //最多99页,0用来存储非白板时的墨迹以便还原
private void SaveStrokes(bool isBackupMain = false) {
if (isBackupMain) {
// 保存每页白板图片信息
private void SaveStrokes(bool isBackupMain = false)
{
// 确保画布上的所有UI元素都被保存到时间机器历史记录中
var currentHistory = timeMachine.ExportTimeMachineHistory();
var elementsInHistory = new HashSet<UIElement>();
// 收集已经在历史记录中的元素
if (currentHistory != null)
{
foreach (var h in currentHistory)
{
if (h.CommitType == TimeMachineHistoryType.ElementInsert &&
h.InsertedElement != null &&
!h.StrokeHasBeenCleared)
{
elementsInHistory.Add(h.InsertedElement);
}
}
}
// 检查画布上的所有UI元素,确保它们都在历史记录中
var missingElements = 0;
foreach (UIElement child in inkCanvas.Children)
{
if (child is Image || child is MediaElement)
{
if (!elementsInHistory.Contains(child))
{
timeMachine.CommitElementInsertHistory(child);
missingElements++;
}
}
}
// 确保画布上的所有墨迹都被保存
if (inkCanvas.Strokes.Count > 0)
{
// 检查是否有墨迹没有在时间机器历史记录中
var strokesInHistory = new HashSet<Stroke>();
if (currentHistory != null)
{
foreach (var h in currentHistory)
{
if (h.CommitType == TimeMachineHistoryType.UserInput &&
h.CurrentStroke != null &&
!h.StrokeHasBeenCleared)
{
foreach (Stroke stroke in h.CurrentStroke)
{
strokesInHistory.Add(stroke);
}
}
}
}
// 收集没有在历史记录中的墨迹
var missingStrokes = new StrokeCollection();
foreach (Stroke stroke in inkCanvas.Strokes)
{
if (!strokesInHistory.Contains(stroke))
{
missingStrokes.Add(stroke);
}
}
if (missingStrokes.Count > 0)
{
timeMachine.CommitStrokeUserInputHistory(missingStrokes);
}
}
if (isBackupMain)
{
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
TimeMachineHistories[0] = timeMachineHistory;
timeMachine.ClearStrokeHistory();
} else {
}
else
{
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
TimeMachineHistories[CurrentWhiteboardIndex] = timeMachineHistory;
timeMachine.ClearStrokeHistory();
}
}
private void ClearStrokes(bool isErasedByCode) {
private void ClearStrokes(bool isErasedByCode)
{
_currentCommitType = CommitReason.ClearingCanvas;
if (isErasedByCode) _currentCommitType = CommitReason.CodeInput;
// 取消任何UI元素的选择,隐藏拉伸控件
DeselectUIElement();
// 只清除笔画,不清除图片元素
// 图片元素的清除由调用方决定
inkCanvas.Strokes.Clear();
_currentCommitType = CommitReason.UserInput;
}
private void RestoreStrokes(bool isBackupMain = false) {
try {
if (TimeMachineHistories[CurrentWhiteboardIndex] == null) return; //防止白板打开后不居中
if (isBackupMain) {
// 恢复每页白板图片信息
private void RestoreStrokes(bool isBackupMain = false)
{
try
{
var targetIndex = isBackupMain ? 0 : CurrentWhiteboardIndex;
// 先清空当前画布的墨迹
inkCanvas.Strokes.Clear();
// 清空当前画布的所有内容(墨迹和图片)
// 这里必须清除图片,因为页面切换时需要完全重置画布状态
inkCanvas.Children.Clear();
// 如果历史记录为空,直接返回(新页面或空页面)
if (TimeMachineHistories[targetIndex] == null)
{
timeMachine.ClearStrokeHistory();
return;
}
if (isBackupMain)
{
timeMachine.ImportTimeMachineHistory(TimeMachineHistories[0]);
foreach (var item in TimeMachineHistories[0]) ApplyHistoryToCanvas(item);
} else {
}
else
{
timeMachine.ImportTimeMachineHistory(TimeMachineHistories[CurrentWhiteboardIndex]);
// 通过时间机器历史恢复所有内容(墨迹和图片)
foreach (var item in TimeMachineHistories[CurrentWhiteboardIndex]) ApplyHistoryToCanvas(item);
}
// 确保选中状态被清除,因为我们切换了页面
if (selectedUIElement != null)
{
DeselectUIElement();
}
}
catch {
catch
{
// ignored
}
}
private async void BtnWhiteBoardPageIndex_Click(object sender, EventArgs e) {
if (sender == BtnLeftPageListWB) {
if (BoardBorderLeftPageListView.Visibility == Visibility.Visible) {
private async void BtnWhiteBoardPageIndex_Click(object sender, EventArgs e)
{
if (sender == BtnLeftPageListWB)
{
if (BoardBorderLeftPageListView.Visibility == Visibility.Visible)
{
AnimationsHelper.HideWithSlideAndFade(BoardBorderLeftPageListView);
} else {
}
else
{
AnimationsHelper.HideWithSlideAndFade(BoardBorderRightPageListView);
RefreshBlackBoardSidePageListView();
AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardBorderLeftPageListView);
@@ -71,11 +189,15 @@ namespace Ink_Canvas {
(ListViewItem)BlackBoardLeftSidePageListView.ItemContainerGenerator.ContainerFromIndex(
CurrentWhiteboardIndex - 1), BlackBoardLeftSidePageListScrollViewer);
}
} else if (sender == BtnRightPageListWB)
}
else if (sender == BtnRightPageListWB)
{
if (BoardBorderRightPageListView.Visibility == Visibility.Visible) {
if (BoardBorderRightPageListView.Visibility == Visibility.Visible)
{
AnimationsHelper.HideWithSlideAndFade(BoardBorderRightPageListView);
} else {
}
else
{
AnimationsHelper.HideWithSlideAndFade(BoardBorderLeftPageListView);
RefreshBlackBoardSidePageListView();
AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardBorderRightPageListView);
@@ -88,9 +210,13 @@ namespace Ink_Canvas {
}
private void BtnWhiteBoardSwitchPrevious_Click(object sender, EventArgs e) {
private void BtnWhiteBoardSwitchPrevious_Click(object sender, EventArgs e)
{
if (CurrentWhiteboardIndex <= 1) return;
// 取消任何UI元素的选择
DeselectUIElement();
SaveStrokes();
ClearStrokes(true);
@@ -101,17 +227,22 @@ namespace Ink_Canvas {
UpdateIndexInfoDisplay();
}
private void BtnWhiteBoardSwitchNext_Click(object sender, EventArgs e) {
private void BtnWhiteBoardSwitchNext_Click(object sender, EventArgs e)
{
Trace.WriteLine("113223234");
if (Settings.Automation.IsAutoSaveStrokesAtClear &&
inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber) SaveScreenShot(true);
if (CurrentWhiteboardIndex >= WhiteboardTotalCount) {
if (CurrentWhiteboardIndex >= WhiteboardTotalCount)
{
// 在最后一页时,点击“新页面”按钮直接新增一页
BtnWhiteBoardAdd_Click(sender, e);
return;
}
// 取消任何UI元素的选择
DeselectUIElement();
SaveStrokes();
ClearStrokes(true);
@@ -122,10 +253,15 @@ namespace Ink_Canvas {
UpdateIndexInfoDisplay();
}
private void BtnWhiteBoardAdd_Click(object sender, EventArgs e) {
private void BtnWhiteBoardAdd_Click(object sender, EventArgs e)
{
if (WhiteboardTotalCount >= 99) return;
if (Settings.Automation.IsAutoSaveStrokesAtClear &&
inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber) SaveScreenShot(true);
// 取消任何UI元素的选择
DeselectUIElement();
SaveStrokes();
ClearStrokes(true);
@@ -136,16 +272,24 @@ namespace Ink_Canvas {
for (var i = WhiteboardTotalCount; i > CurrentWhiteboardIndex; i--)
TimeMachineHistories[i] = TimeMachineHistories[i - 1];
// 确保新页面的历史记录为空
TimeMachineHistories[CurrentWhiteboardIndex] = null;
// 恢复新页面(这会清空画布,因为历史记录为null)
RestoreStrokes();
UpdateIndexInfoDisplay();
if (WhiteboardTotalCount >= 99) BtnWhiteBoardAdd.IsEnabled = false;
if (BlackBoardLeftSidePageListView.Visibility == Visibility.Visible) {
if (BlackBoardLeftSidePageListView.Visibility == Visibility.Visible)
{
RefreshBlackBoardSidePageListView();
}
}
private void BtnWhiteBoardDelete_Click(object sender, RoutedEventArgs e) {
private void BtnWhiteBoardDelete_Click(object sender, RoutedEventArgs e)
{
ClearStrokes(true);
if (CurrentWhiteboardIndex != WhiteboardTotalCount)
@@ -163,7 +307,8 @@ namespace Ink_Canvas {
if (WhiteboardTotalCount < 99) BtnWhiteBoardAdd.IsEnabled = true;
}
private void UpdateIndexInfoDisplay() {
private void UpdateIndexInfoDisplay()
{
TextBlockWhiteBoardIndexInfo.Text =
$"{CurrentWhiteboardIndex}/{WhiteboardTotalCount}";
@@ -185,13 +330,16 @@ namespace Ink_Canvas {
BtnWhiteBoardSwitchPrevious.IsEnabled = true;
if (CurrentWhiteboardIndex == 1) {
if (CurrentWhiteboardIndex == 1)
{
BtnWhiteBoardSwitchPrevious.IsEnabled = false;
BtnLeftWhiteBoardSwitchPreviousGeometry.Brush = new SolidColorBrush(Color.FromArgb(127, 24, 24, 27));
BtnLeftWhiteBoardSwitchPreviousLabel.Opacity = 0.5;
BtnRightWhiteBoardSwitchPreviousGeometry.Brush = new SolidColorBrush(Color.FromArgb(127, 24, 24, 27));
BtnRightWhiteBoardSwitchPreviousLabel.Opacity = 0.5;
} else {
}
else
{
BtnLeftWhiteBoardSwitchPreviousGeometry.Brush = new SolidColorBrush(Color.FromArgb(255, 24, 24, 27));
BtnLeftWhiteBoardSwitchPreviousLabel.Opacity = 1;
BtnRightWhiteBoardSwitchPreviousGeometry.Brush = new SolidColorBrush(Color.FromArgb(255, 24, 24, 27));
+799 -69
View File
@@ -1,126 +1,856 @@
using Ink_Canvas.Helpers;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Ink_Canvas {
public partial class MainWindow : Window {
private void BoardChangeBackgroundColorBtn_MouseUp(object sender, RoutedEventArgs e) {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private void BoardChangeBackgroundColorBtn_MouseUp(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
// 创建背景选项面板(如果不存在)
if (BackgroundPalette == null)
{
CreateBackgroundPalette();
}
// 显示或隐藏背景选项面板
if (BackgroundPalette != null)
{
if (BackgroundPalette.Visibility == Visibility.Visible)
{
// 如果面板已经显示,则隐藏它
AnimationsHelper.HideWithSlideAndFade(BackgroundPalette);
}
else
{
// 隐藏其他可能显示的面板
AnimationsHelper.HideWithSlideAndFade(EraserSizePanel);
AnimationsHelper.HideWithSlideAndFade(BorderTools);
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
AnimationsHelper.HideWithSlideAndFade(PenPalette);
AnimationsHelper.HideWithSlideAndFade(BoardPenPalette);
AnimationsHelper.HideWithSlideAndFade(BorderDrawShape);
AnimationsHelper.HideWithSlideAndFade(BoardBorderDrawShape);
AnimationsHelper.HideWithSlideAndFade(BoardEraserSizePanel);
AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
// 显示背景选项面板
AnimationsHelper.ShowWithSlideFromBottomAndFade(BackgroundPalette);
}
return;
}
// 原有的背景切换代码
Settings.Canvas.UsingWhiteboard = !Settings.Canvas.UsingWhiteboard;
SaveSettingsToFile();
if (Settings.Canvas.UsingWhiteboard) {
if (Settings.Canvas.UsingWhiteboard)
{
if (inkColor == 5) lastBoardInkColor = 0;
ICCWaterMarkDark.Visibility = Visibility.Visible;
ICCWaterMarkWhite.Visibility = Visibility.Collapsed;
// 设置为白板默认背景色
Color defaultWhiteboardColor = Color.FromRgb(234, 235, 237);
if (currentMode == 1) // 白板模式
{
// 设置背景为默认白板背景色
GridBackgroundCover.Background = new SolidColorBrush(defaultWhiteboardColor);
// 更新RGB滑块的值为默认白板背景色
if (BackgroundPalette != null && BackgroundPalette.Visibility == Visibility.Visible)
{
UpdateRGBSliders(defaultWhiteboardColor);
}
// 更新自定义背景色为默认白板背景色
CustomBackgroundColor = defaultWhiteboardColor;
// 保存到设置
string colorHex = $"#{defaultWhiteboardColor.R:X2}{defaultWhiteboardColor.G:X2}{defaultWhiteboardColor.B:X2}";
Settings.Canvas.CustomBackgroundColor = colorHex;
SaveSettingsToFile();
}
// 设置墨迹颜色为黑色
CheckLastColor(0);
forceEraser = false;
}
else {
else
{
if (inkColor == 0) lastBoardInkColor = 5;
ICCWaterMarkWhite.Visibility = Visibility.Visible;
ICCWaterMarkDark.Visibility = Visibility.Collapsed;
// 设置为黑板默认背景色
Color defaultBlackboardColor = Color.FromRgb(22, 41, 36);
if (currentMode == 1) // 黑板模式
{
// 设置背景为默认黑板背景色
GridBackgroundCover.Background = new SolidColorBrush(defaultBlackboardColor);
// 更新RGB滑块的值为默认黑板背景色
if (BackgroundPalette != null && BackgroundPalette.Visibility == Visibility.Visible)
{
UpdateRGBSliders(defaultBlackboardColor);
}
// 更新自定义背景色为默认黑板背景色
CustomBackgroundColor = defaultBlackboardColor;
// 保存到设置
string colorHex = $"#{defaultBlackboardColor.R:X2}{defaultBlackboardColor.G:X2}{defaultBlackboardColor.B:X2}";
Settings.Canvas.CustomBackgroundColor = colorHex;
SaveSettingsToFile();
}
// 设置墨迹颜色为白色
CheckLastColor(5);
forceEraser = false;
}
CheckColorTheme(true);
}
private void BoardEraserIcon_Click(object sender, RoutedEventArgs e) {
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint ||
inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke) {
if (BoardEraserSizePanel.Visibility == Visibility.Collapsed) {
AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardEraserSizePanel);
} else {
AnimationsHelper.HideWithSlideAndFade(BoardEraserSizePanel);
}
} else {
forceEraser = true;
forcePointEraser = true;
double k = 1;
if (Settings.Canvas.EraserShapeType == 0) {
switch (BoardComboBoxEraserSize.SelectedIndex)
{
case 0:
k = 0.5;
break;
case 1:
k = 0.8;
break;
case 3:
k = 1.25;
break;
case 4:
k = 1.8;
break;
}
inkCanvas.EraserShape = new EllipseStylusShape(k * 90, k * 90);
} else if (Settings.Canvas.EraserShapeType == 1) {
switch (BoardComboBoxEraserSize.SelectedIndex)
{
case 0:
k = 0.7;
break;
case 1:
k = 0.9;
break;
case 3:
k = 1.2;
break;
case 4:
k = 1.6;
break;
}
inkCanvas.EraserShape = new RectangleStylusShape(k * 90 * 0.6, k * 90);
}
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
drawingShapeMode = 0;
// 创建背景选项面板
private void CreateBackgroundPalette()
{
// 确保加载自定义背景色
LoadCustomBackgroundColor();
inkCanvas_EditingModeChanged(inkCanvas, null);
CancelSingleFingerDragMode();
// 创建一个类似于PenPalette的面板
BackgroundPalette = new Border
{
Name = "BackgroundPalette",
Visibility = Visibility.Collapsed,
Background = new SolidColorBrush(Colors.White),
Opacity = 1,
BorderBrush = new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Width = 300,
MaxHeight = 400
};
HideSubPanels("eraser");
// 确保面板显示在顶层
Panel.SetZIndex(BackgroundPalette, 1000);
// 创建面板内容
var stackPanel = new StackPanel();
// 创建标题栏
var titleBorder = new Border
{
BorderBrush = new SolidColorBrush(Color.FromRgb(0x1e, 0x3a, 0x8a)),
Height = 32,
BorderThickness = new Thickness(0, 0, 0, 1),
CornerRadius = new CornerRadius(8, 8, 0, 0),
Background = new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)),
Margin = new Thickness(-1, -1, -1, 0),
Padding = new Thickness(1, 1, 1, 0)
};
var titleCanvas = new System.Windows.Controls.Canvas { Height = 24, ClipToBounds = true };
var titleText = new TextBlock
{
Text = "背景设置",
Foreground = new SolidColorBrush(Colors.White),
Padding = new Thickness(0, 5, 0, 0),
FontSize = 11,
FontWeight = FontWeights.Bold,
TextAlignment = TextAlignment.Center
};
System.Windows.Controls.Canvas.SetLeft(titleText, 8);
titleCanvas.Children.Add(titleText);
// 关闭按钮
var closeImage = new Image
{
Source = new BitmapImage(new Uri("/Resources/new-icons/close-white.png", UriKind.Relative)),
Height = 16,
Width = 16
};
RenderOptions.SetBitmapScalingMode(closeImage, BitmapScalingMode.HighQuality);
closeImage.MouseUp += CloseBordertools_MouseUp;
System.Windows.Controls.Canvas.SetRight(closeImage, 8);
System.Windows.Controls.Canvas.SetTop(closeImage, 4);
titleCanvas.Children.Add(closeImage);
titleBorder.Child = titleCanvas;
stackPanel.Children.Add(titleBorder);
// 创建背景选项内容区域
var contentPanel = new StackPanel { Margin = new Thickness(8) };
// 黑板/白板选择
var modeTitle = new TextBlock
{
Text = "白板模式",
Foreground = new SolidColorBrush(Color.FromRgb(0x17, 0x25, 0x54)),
FontSize = 10,
FontWeight = FontWeights.Bold,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0, 4, 0, 8)
};
contentPanel.Children.Add(modeTitle);
var modePanel = new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center };
// 白板按钮
var whiteboardButton = new Border
{
Width = 60,
Height = 30,
Background = Settings.Canvas.UsingWhiteboard ? new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)) : new SolidColorBrush(Colors.LightGray),
CornerRadius = new CornerRadius(4),
Margin = new Thickness(0, 0, 8, 0)
};
var whiteboardText = new TextBlock
{
Text = "白板",
Foreground = Settings.Canvas.UsingWhiteboard ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Colors.Black),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
whiteboardButton.Child = whiteboardText;
whiteboardButton.MouseUp += (s, args) =>
{
Settings.Canvas.UsingWhiteboard = true;
SaveSettingsToFile();
ICCWaterMarkDark.Visibility = Visibility.Visible;
ICCWaterMarkWhite.Visibility = Visibility.Collapsed;
// 设置为白板默认背景色
Color defaultWhiteboardColor = Color.FromRgb(234, 235, 237);
if (currentMode == 1) // 白板模式
{
// 设置背景为默认白板背景色
GridBackgroundCover.Background = new SolidColorBrush(defaultWhiteboardColor);
// 更新RGB滑块的值为默认白板背景色
UpdateRGBSliders(defaultWhiteboardColor);
// 更新自定义背景色为默认白板背景色
CustomBackgroundColor = defaultWhiteboardColor;
// 保存到设置
string colorHex = $"#{defaultWhiteboardColor.R:X2}{defaultWhiteboardColor.G:X2}{defaultWhiteboardColor.B:X2}";
Settings.Canvas.CustomBackgroundColor = colorHex;
SaveSettingsToFile();
}
// 设置墨迹颜色为黑色
CheckLastColor(0);
forceEraser = false;
CheckColorTheme(true);
UpdateBackgroundButtonsState();
};
modePanel.Children.Add(whiteboardButton);
// 黑板按钮
var blackboardButton = new Border
{
Width = 60,
Height = 30,
Background = !Settings.Canvas.UsingWhiteboard ? new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)) : new SolidColorBrush(Colors.LightGray),
CornerRadius = new CornerRadius(4)
};
var blackboardText = new TextBlock
{
Text = "黑板",
Foreground = !Settings.Canvas.UsingWhiteboard ? new SolidColorBrush(Colors.White) : new SolidColorBrush(Colors.Black),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center
};
blackboardButton.Child = blackboardText;
blackboardButton.MouseUp += (s, args) =>
{
Settings.Canvas.UsingWhiteboard = false;
SaveSettingsToFile();
ICCWaterMarkWhite.Visibility = Visibility.Visible;
ICCWaterMarkDark.Visibility = Visibility.Collapsed;
// 设置为黑板默认背景色
Color defaultBlackboardColor = Color.FromRgb(22, 41, 36);
if (currentMode == 1) // 黑板模式
{
// 设置背景为默认黑板背景色
GridBackgroundCover.Background = new SolidColorBrush(defaultBlackboardColor);
// 更新RGB滑块的值为默认黑板背景色
UpdateRGBSliders(defaultBlackboardColor);
// 更新自定义背景色为默认黑板背景色
CustomBackgroundColor = defaultBlackboardColor;
// 保存到设置
string colorHex = $"#{defaultBlackboardColor.R:X2}{defaultBlackboardColor.G:X2}{defaultBlackboardColor.B:X2}";
Settings.Canvas.CustomBackgroundColor = colorHex;
SaveSettingsToFile();
}
// 设置墨迹颜色为白色
CheckLastColor(5);
forceEraser = false;
CheckColorTheme(true);
UpdateBackgroundButtonsState();
};
modePanel.Children.Add(blackboardButton);
contentPanel.Children.Add(modePanel);
// 添加一条分隔线
var separator = new Border
{
Height = 1,
Background = new SolidColorBrush(Color.FromRgb(0xd4, 0xd4, 0xd8)),
Margin = new Thickness(0, 12, 0, 12)
};
contentPanel.Children.Add(separator);
// 添加RGB颜色选择器部分
var colorTitle = new TextBlock
{
Text = "背景颜色",
Foreground = new SolidColorBrush(Color.FromRgb(0x17, 0x25, 0x54)),
FontSize = 10,
FontWeight = FontWeights.Bold,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0, 4, 0, 8)
};
contentPanel.Children.Add(colorTitle);
// 创建颜色预览
Border colorPreview = new Border
{
Width = 100,
Height = 40,
BorderThickness = new Thickness(1),
BorderBrush = new SolidColorBrush(Color.FromRgb(0xd4, 0xd4, 0xd8)),
Background = new SolidColorBrush(Colors.White),
CornerRadius = new CornerRadius(4),
Margin = new Thickness(0, 0, 0, 10),
HorizontalAlignment = HorizontalAlignment.Center
};
contentPanel.Children.Add(colorPreview);
// 获取当前背景颜色
Color currentBackgroundColor;
if (currentMode == 1) // 白板或黑板模式
{
if (GridBackgroundCover.Background is SolidColorBrush brush)
{
currentBackgroundColor = brush.Color;
}
else
{
// 默认颜色
currentBackgroundColor = Settings.Canvas.UsingWhiteboard ?
Color.FromRgb(234, 235, 237) : // 白板默认颜色
Color.FromRgb(22, 41, 36); // 黑板默认颜色
}
}
else
{
// 默认白色
currentBackgroundColor = Colors.White;
}
// 更新颜色预览
colorPreview.Background = new SolidColorBrush(currentBackgroundColor);
// 先创建所有滑块控件
// R滑块和文本框
var rPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(10, 0, 10, 5) };
var rLabel = new TextBlock { Text = "R:", Width = 20, VerticalAlignment = VerticalAlignment.Center };
var rSlider = new Slider
{
Minimum = 0,
Maximum = 255,
Value = currentBackgroundColor.R,
Width = 150,
Margin = new Thickness(5, 0, 5, 0),
VerticalAlignment = VerticalAlignment.Center
};
var rValueText = new TextBlock
{
Text = currentBackgroundColor.R.ToString(),
Width = 30,
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Right
};
// G滑块和文本框
var gPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(10, 0, 10, 5) };
var gLabel = new TextBlock { Text = "G:", Width = 20, VerticalAlignment = VerticalAlignment.Center };
var gSlider = new Slider
{
Minimum = 0,
Maximum = 255,
Value = currentBackgroundColor.G,
Width = 150,
Margin = new Thickness(5, 0, 5, 0),
VerticalAlignment = VerticalAlignment.Center
};
var gValueText = new TextBlock
{
Text = currentBackgroundColor.G.ToString(),
Width = 30,
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Right
};
// B滑块和文本框
var bPanel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(10, 0, 10, 5) };
var bLabel = new TextBlock { Text = "B:", Width = 20, VerticalAlignment = VerticalAlignment.Center };
var bSlider = new Slider
{
Minimum = 0,
Maximum = 255,
Value = currentBackgroundColor.B,
Width = 150,
Margin = new Thickness(5, 0, 5, 0),
VerticalAlignment = VerticalAlignment.Center
};
var bValueText = new TextBlock
{
Text = currentBackgroundColor.B.ToString(),
Width = 30,
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Right
};
// 现在添加事件处理程序
rSlider.ValueChanged += (s, e) =>
{
int value = (int)e.NewValue;
rValueText.Text = value.ToString();
UpdateColorPreview(colorPreview, rSlider, gSlider, bSlider);
};
gSlider.ValueChanged += (s, e) =>
{
int value = (int)e.NewValue;
gValueText.Text = value.ToString();
UpdateColorPreview(colorPreview, rSlider, gSlider, bSlider);
};
bSlider.ValueChanged += (s, e) =>
{
int value = (int)e.NewValue;
bValueText.Text = value.ToString();
UpdateColorPreview(colorPreview, rSlider, gSlider, bSlider);
};
// 添加控件到面板
rPanel.Children.Add(rLabel);
rPanel.Children.Add(rSlider);
rPanel.Children.Add(rValueText);
contentPanel.Children.Add(rPanel);
gPanel.Children.Add(gLabel);
gPanel.Children.Add(gSlider);
gPanel.Children.Add(gValueText);
contentPanel.Children.Add(gPanel);
bPanel.Children.Add(bLabel);
bPanel.Children.Add(bSlider);
bPanel.Children.Add(bValueText);
contentPanel.Children.Add(bPanel);
// 应用按钮
var applyButton = new Button
{
Content = "应用颜色",
Margin = new Thickness(0, 10, 0, 0),
Padding = new Thickness(10, 5, 10, 5),
Background = new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)),
Foreground = new SolidColorBrush(Colors.White),
BorderThickness = new Thickness(0),
HorizontalAlignment = HorizontalAlignment.Center
};
applyButton.Click += (s, e) =>
{
Color selectedColor = Color.FromRgb(
(byte)rSlider.Value,
(byte)gSlider.Value,
(byte)bSlider.Value
);
ApplyCustomBackgroundColor(selectedColor);
};
contentPanel.Children.Add(applyButton);
stackPanel.Children.Add(contentPanel);
// 将面板添加到父容器
BackgroundPalette.Child = stackPanel;
// 获取主窗口中的根网格,确保面板添加到顶层
Grid mainGrid = FindName("Main_Grid") as Grid;
if (mainGrid != null)
{
// 删除可能已存在的BackgroundPalette
foreach (UIElement element in mainGrid.Children)
{
if (element is Border border && border.Name == "BackgroundPalette")
{
mainGrid.Children.Remove(border);
break;
}
}
// 重新定位面板
BackgroundPalette.HorizontalAlignment = HorizontalAlignment.Center;
BackgroundPalette.VerticalAlignment = VerticalAlignment.Center;
BackgroundPalette.Margin = new Thickness(0, 0, 0, 0);
// 添加到主网格
mainGrid.Children.Add(BackgroundPalette);
// 设置面板位置
var clickElement = FindName("BoardChangeBackgroundColorBtn") as FrameworkElement;
if (clickElement != null)
{
Point position = clickElement.TranslatePoint(new Point(0, 0), mainGrid);
BackgroundPalette.Margin = new Thickness(
position.X - 150,
position.Y + clickElement.ActualHeight + 5,
0, 0);
BackgroundPalette.HorizontalAlignment = HorizontalAlignment.Left;
BackgroundPalette.VerticalAlignment = VerticalAlignment.Top;
}
}
}
private void BoardEraserIconByStrokes_Click(object sender, RoutedEventArgs e) {
// 更新背景按钮状态
private void UpdateBackgroundButtonsState()
{
if (BackgroundPalette != null && BackgroundPalette.Child is StackPanel stackPanel)
{
if (stackPanel.Children.Count > 1 && stackPanel.Children[1] is StackPanel contentPanel)
{
if (contentPanel.Children.Count > 1 && contentPanel.Children[1] is StackPanel modePanel)
{
if (modePanel.Children.Count > 1)
{
var whiteboardButton = modePanel.Children[0] as Border;
var blackboardButton = modePanel.Children[1] as Border;
if (whiteboardButton != null && whiteboardButton.Child is TextBlock whiteboardText)
{
whiteboardButton.Background = Settings.Canvas.UsingWhiteboard ?
new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)) :
new SolidColorBrush(Colors.LightGray);
whiteboardText.Foreground = Settings.Canvas.UsingWhiteboard ?
new SolidColorBrush(Colors.White) :
new SolidColorBrush(Colors.Black);
}
if (blackboardButton != null && blackboardButton.Child is TextBlock blackboardText)
{
blackboardButton.Background = !Settings.Canvas.UsingWhiteboard ?
new SolidColorBrush(Color.FromRgb(0x25, 0x63, 0xeb)) :
new SolidColorBrush(Colors.LightGray);
blackboardText.Foreground = !Settings.Canvas.UsingWhiteboard ?
new SolidColorBrush(Colors.White) :
new SolidColorBrush(Colors.Black);
}
}
}
}
}
}
// 添加成员变量保存背景面板引用
private Border BackgroundPalette { get; set; }
// 添加成员变量保存当前自定义背景色
private Color? CustomBackgroundColor { get; set; }
/// <summary>
/// 更新颜色预览框的颜色
/// </summary>
private void UpdateColorPreview(Border colorPreview, Slider rSlider, Slider gSlider, Slider bSlider)
{
Color previewColor = Color.FromRgb(
(byte)rSlider.Value,
(byte)gSlider.Value,
(byte)bSlider.Value
);
colorPreview.Background = new SolidColorBrush(previewColor);
}
/// <summary>
/// 应用自定义背景颜色
/// </summary>
private void ApplyCustomBackgroundColor(Color color)
{
// 保存当前选择的颜色
CustomBackgroundColor = color;
// 将颜色转换为十六进制字符串并保存到设置中
string colorHex = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
Settings.Canvas.CustomBackgroundColor = colorHex;
// 只在白板或黑板模式下应用自定义背景色
if (currentMode == 1) // 白板或黑板模式
{
// 设置白板/黑板模式下的背景
GridBackgroundCover.Background = new SolidColorBrush(color);
}
// 保存设置
SaveSettingsToFile();
// 立即更新界面
if (BackgroundPalette != null)
{
UpdateBackgroundButtonsState();
UpdateRGBSliders(color); // 更新RGB滑块的值
}
// 显示提示信息
ShowNotification($"已应用自定义背景色: {colorHex}");
}
/// <summary>
/// 从设置中加载自定义背景色
/// </summary>
private void LoadCustomBackgroundColor()
{
if (!string.IsNullOrEmpty(Settings.Canvas.CustomBackgroundColor))
{
try
{
// 解析颜色字符串
string colorHex = Settings.Canvas.CustomBackgroundColor;
if (colorHex.StartsWith("#") && colorHex.Length == 7) // #RRGGBB 格式
{
byte r = Convert.ToByte(colorHex.Substring(1, 2), 16);
byte g = Convert.ToByte(colorHex.Substring(3, 2), 16);
byte b = Convert.ToByte(colorHex.Substring(5, 2), 16);
// 保存到内存中
CustomBackgroundColor = Color.FromRgb(r, g, b);
}
}
catch (Exception ex)
{
// 解析失败,根据当前模式设置默认颜色
if (!Settings.Canvas.UsingWhiteboard)
{
// 黑板模式默认颜色
CustomBackgroundColor = Color.FromRgb(22, 41, 36);
}
else
{
// 白板模式默认颜色
CustomBackgroundColor = Color.FromRgb(234, 235, 237);
}
// 可以在这里记录日志
Console.WriteLine($"解析自定义背景色失败: {ex.Message}");
}
}
else
{
// 如果没有设置自定义背景色,根据当前模式设置默认颜色
if (!Settings.Canvas.UsingWhiteboard)
{
// 黑板模式默认颜色
CustomBackgroundColor = Color.FromRgb(22, 41, 36);
}
else
{
// 白板模式默认颜色
CustomBackgroundColor = Color.FromRgb(234, 235, 237);
}
}
// 只在白板或黑板模式下应用自定义背景色
if (currentMode == 1 && CustomBackgroundColor.HasValue) // 白板或黑板模式
{
// 设置白板/黑板模式下的背景
GridBackgroundCover.Background = new SolidColorBrush(CustomBackgroundColor.Value);
// 更新RGB滑块的值(如果调色板已经创建)
if (BackgroundPalette != null && BackgroundPalette.Visibility == Visibility.Visible)
{
UpdateRGBSliders(CustomBackgroundColor.Value);
}
}
}
private void BoardLassoIcon_Click(object sender, RoutedEventArgs e)
{
forceEraser = false;
forcePointEraser = false;
drawingShapeMode = 0;
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
SetCursorBasedOnEditingMode(inkCanvas);
}
private void BoardEraserIconByStrokes_Click(object sender, RoutedEventArgs e)
{
//if (BoardEraserByStrokes.Background.ToString() == "#FF679CF4") {
// AnimationsHelper.ShowWithSlideFromBottomAndFade(BoardDeleteIcon);
//}
//else {
forceEraser = true;
forcePointEraser = false;
// 禁用高级橡皮擦系统
DisableAdvancedEraserSystem();
inkCanvas.EraserShape = new EllipseStylusShape(5, 5);
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
drawingShapeMode = 0;
forceEraser = true;
forcePointEraser = false;
inkCanvas_EditingModeChanged(inkCanvas, null);
CancelSingleFingerDragMode();
inkCanvas.EraserShape = new EllipseStylusShape(5, 5);
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
drawingShapeMode = 0;
HideSubPanels("eraserByStrokes");
// 修复:切换到线擦时,确保重置笔的状态
penType = 0;
drawingAttributes.IsHighlighter = false;
drawingAttributes.StylusTip = StylusTip.Ellipse;
inkCanvas_EditingModeChanged(inkCanvas, null);
CancelSingleFingerDragMode();
HideSubPanels("eraserByStrokes");
//}
}
private void BoardSymbolIconDelete_MouseUp(object sender, RoutedEventArgs e) {
private void BoardSymbolIconDelete_MouseUp(object sender, RoutedEventArgs e)
{
PenIcon_Click(null, null);
SymbolIconDelete_MouseUp(null, null);
// 根据设置决定是否清空图片
if (Settings.Canvas.ClearCanvasAlsoClearImages)
{
// 如果设置为清空图片,则直接清空所有子元素
Debug.WriteLine("BoardSymbolIconDelete: Clearing all children including images");
inkCanvas.Children.Clear();
}
else
{
// 保存非笔画元素(如图片)
Debug.WriteLine("BoardSymbolIconDelete: Preserving non-stroke elements (images)");
var preservedElements = PreserveNonStrokeElements();
Debug.WriteLine($"BoardSymbolIconDelete: Preserved elements count: {preservedElements.Count}");
inkCanvas.Children.Clear();
// 恢复非笔画元素
RestoreNonStrokeElements(preservedElements);
Debug.WriteLine($"BoardSymbolIconDelete: inkCanvas.Children.Count after restore: {inkCanvas.Children.Count}");
}
}
private void BoardSymbolIconDeleteInkAndHistories_MouseUp(object sender, RoutedEventArgs e)
{
PenIcon_Click(null, null);
SymbolIconDelete_MouseUp(null, null);
if (Settings.Canvas.ClearCanvasAndClearTimeMachine == false) timeMachine.ClearStrokeHistory();
// 根据设置决定是否清空图片
if (Settings.Canvas.ClearCanvasAlsoClearImages)
{
// 如果设置为清空图片,则直接清空所有子元素
Debug.WriteLine("BoardSymbolIconDeleteInkAndHistories: Clearing all children including images");
inkCanvas.Children.Clear();
}
else
{
// 保存非笔画元素(如图片)
Debug.WriteLine("BoardSymbolIconDeleteInkAndHistories: Preserving non-stroke elements (images)");
var preservedElements = PreserveNonStrokeElements();
Debug.WriteLine($"BoardSymbolIconDeleteInkAndHistories: Preserved elements count: {preservedElements.Count}");
inkCanvas.Children.Clear();
// 恢复非笔画元素
RestoreNonStrokeElements(preservedElements);
Debug.WriteLine($"BoardSymbolIconDeleteInkAndHistories: inkCanvas.Children.Count after restore: {inkCanvas.Children.Count}");
}
}
private void BoardLaunchEasiCamera_MouseUp(object sender, MouseButtonEventArgs e) {
private void BoardLaunchEasiCamera_MouseUp(object sender, MouseButtonEventArgs e)
{
ImageBlackboard_MouseUp(null, null);
SoftwareLauncher.LaunchEasiCamera("希沃视频展台");
}
private void BoardLaunchDesmos_MouseUp(object sender, MouseButtonEventArgs e) {
private void BoardLaunchDesmos_MouseUp(object sender, MouseButtonEventArgs e)
{
HideSubPanelsImmediately();
ImageBlackboard_MouseUp(null, null);
Process.Start("https://www.desmos.com/calculator?lang=zh-CN");
}
/// <summary>
/// 根据当前背景颜色更新RGB滑块的值
/// </summary>
private void UpdateRGBSliders(Color color)
{
if (BackgroundPalette != null && BackgroundPalette.Child is StackPanel stackPanel)
{
if (stackPanel.Children.Count > 1 && stackPanel.Children[1] is StackPanel contentPanel)
{
// 查找RGB滑块
Slider rSlider = null;
Slider gSlider = null;
Slider bSlider = null;
// 遍历面板查找RGB滑块
foreach (var child in contentPanel.Children)
{
if (child is StackPanel panel && panel.Orientation == Orientation.Horizontal)
{
foreach (var panelChild in panel.Children)
{
if (panelChild is Slider slider)
{
if (panel.Children.Count > 0 && panel.Children[0] is TextBlock label)
{
if (label.Text == "R:")
{
rSlider = slider;
}
else if (label.Text == "G:")
{
gSlider = slider;
}
else if (label.Text == "B:")
{
bSlider = slider;
}
}
}
}
}
}
// 更新滑块值
if (rSlider != null && gSlider != null && bSlider != null)
{
rSlider.Value = color.R;
gSlider.Value = color.G;
bSlider.Value = color.B;
}
}
}
}
}
}
@@ -0,0 +1,267 @@
using Ink_Canvas.Helpers;
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private bool isClipboardMonitoringEnabled = false;
private BitmapSource lastClipboardImage = null;
// 初始化剪贴板监控
private void InitializeClipboardMonitoring()
{
try
{
// 监听剪贴板变化
ClipboardNotification.ClipboardUpdate += OnClipboardUpdate;
isClipboardMonitoringEnabled = true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化剪贴板监控失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 剪贴板内容变化事件处理
private void OnClipboardUpdate()
{
try
{
if (Clipboard.ContainsImage())
{
var clipboardImage = Clipboard.GetImage();
if (clipboardImage != null && clipboardImage != lastClipboardImage)
{
lastClipboardImage = clipboardImage;
// 在白板模式下显示粘贴提示
if (currentMode == 1) // 白板模式
{
ShowPasteNotification();
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理剪贴板更新失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 显示粘贴提示
private void ShowPasteNotification()
{
try
{
Dispatcher.Invoke(() =>
{
ShowNotification("检测到剪贴板中有图片,右键点击白板可粘贴");
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示粘贴提示失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理右键菜单显示
private void ShowPasteContextMenu(Point position)
{
try
{
if (!Clipboard.ContainsImage()) return;
// 创建右键菜单
var contextMenu = new ContextMenu();
var pasteMenuItem = new MenuItem
{
Header = "粘贴图片"
};
pasteMenuItem.Click += async (s, e) => await PasteImageFromClipboard(position);
contextMenu.Items.Add(pasteMenuItem);
// 显示菜单
contextMenu.IsOpen = true;
contextMenu.PlacementTarget = inkCanvas;
contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示粘贴菜单失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 从剪贴板粘贴图片
private async Task PasteImageFromClipboard(Point? position = null)
{
try
{
if (!Clipboard.ContainsImage())
{
ShowNotification("剪贴板中没有图片");
return;
}
var clipboardImage = Clipboard.GetImage();
if (clipboardImage == null)
{
ShowNotification("无法获取剪贴板图片");
return;
}
// 创建Image控件
var image = new Image
{
Source = clipboardImage,
Width = clipboardImage.PixelWidth,
Height = clipboardImage.PixelHeight,
Stretch = System.Windows.Media.Stretch.Fill
};
// 生成唯一名称
string timestamp = "img_clipboard_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
image.Name = timestamp;
// 设置位置
if (position.HasValue)
{
// 在指定位置居中显示
InkCanvas.SetLeft(image, position.Value.X - image.Width / 2);
InkCanvas.SetTop(image, position.Value.Y - image.Height / 2);
}
else
{
// 使用与文件选择相同的居中和缩放逻辑
CenterAndScaleElement(image);
}
// 添加到画布
inkCanvas.Children.Add(image);
// 添加鼠标事件处理
image.MouseDown += UIElement_MouseDown;
image.IsManipulationEnabled = true;
// 提交到历史记录
timeMachine.CommitElementInsertHistory(image);
ShowNotification("图片已从剪贴板粘贴");
}
catch (Exception ex)
{
ShowNotification($"粘贴图片失败: {ex.Message}");
LogHelper.WriteLogToFile($"粘贴图片失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理白板右键事件
private void InkCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
try
{
// 只在白板模式下处理
if (currentMode != 1) return;
// 检查是否有图片在剪贴板中
if (Clipboard.ContainsImage())
{
var position = e.GetPosition(inkCanvas);
ShowPasteContextMenu(position);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理右键事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 处理全局粘贴快捷键
private async void HandleGlobalPaste(object sender, ExecutedRoutedEventArgs e)
{
try
{
// 只在白板模式下处理
if (currentMode != 1) return;
if (Clipboard.ContainsImage())
{
await PasteImageFromClipboard();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理全局粘贴失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 清理剪贴板监控
private void CleanupClipboardMonitoring()
{
try
{
if (isClipboardMonitoringEnabled)
{
ClipboardNotification.ClipboardUpdate -= OnClipboardUpdate;
isClipboardMonitoringEnabled = false;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理剪贴板监控失败: {ex.Message}", LogHelper.LogType.Error);
}
}
}
// 剪贴板通知类
public static class ClipboardNotification
{
public static event Action ClipboardUpdate;
private static System.Windows.Forms.Timer clipboardTimer;
private static string lastClipboardText = "";
private static bool lastHadImage = false;
static ClipboardNotification()
{
clipboardTimer = new System.Windows.Forms.Timer();
clipboardTimer.Interval = 500; // 每500ms检查一次
clipboardTimer.Tick += CheckClipboard;
clipboardTimer.Start();
}
private static void CheckClipboard(object sender, EventArgs e)
{
try
{
bool currentHasImage = Clipboard.ContainsImage();
string currentText = Clipboard.ContainsText() ? Clipboard.GetText() : "";
if (currentHasImage != lastHadImage || currentText != lastClipboardText)
{
lastHadImage = currentHasImage;
lastClipboardText = currentText;
ClipboardUpdate?.Invoke();
}
}
catch
{
// 忽略剪贴板访问错误
}
}
public static void Stop()
{
clipboardTimer?.Stop();
clipboardTimer?.Dispose();
}
}
}
+147 -88
View File
@@ -1,25 +1,28 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Ink_Canvas {
public partial class MainWindow : Window {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private int inkColor = 1;
private void ColorSwitchCheck() {
private void ColorSwitchCheck()
{
HideSubPanels("color");
if (GridTransparencyFakeBackground.Background == Brushes.Transparent) {
if (currentMode == 1) {
if (GridTransparencyFakeBackground.Background == Brushes.Transparent)
{
if (currentMode == 1)
{
currentMode = 0;
GridBackgroundCover.Visibility = Visibility.Collapsed;
AnimationsHelper.HideWithSlideAndFade(BlackboardLeftSide);
@@ -31,12 +34,15 @@ namespace Ink_Canvas {
}
var strokes = inkCanvas.GetSelectedStrokes();
if (strokes.Count != 0) {
if (strokes.Count != 0)
{
foreach (var stroke in strokes)
try {
try
{
stroke.DrawingAttributes.Color = inkCanvas.DefaultDrawingAttributes.Color;
}
catch {
catch
{
// ignored
}
}
@@ -49,35 +55,55 @@ namespace Ink_Canvas {
item.Value.Clear();
}
}
else {
else
{
inkCanvas.IsManipulationEnabled = true;
drawingShapeMode = 0;
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
CancelSingleFingerDragMode();
forceEraser = false;
CheckColorTheme();
}
isLongPressSelected = false;
}
private bool isUselightThemeColor = false, isDesktopUselightThemeColor = false;
private int penType = 0; // 0是签字笔,1是荧光笔
private bool isUselightThemeColor, isDesktopUselightThemeColor;
private int penType; // 0是签字笔,1是荧光笔
private int lastDesktopInkColor = 1, lastBoardInkColor = 5;
private int highlighterColor = 102;
private void CheckColorTheme(bool changeColorTheme = false) {
private void CheckColorTheme(bool changeColorTheme = false)
{
if (changeColorTheme)
if (currentMode != 0) {
if (Settings.Canvas.UsingWhiteboard) {
GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(234, 235, 237));
if (currentMode != 0)
{
if (Settings.Canvas.UsingWhiteboard)
{
// 检查是否有自定义背景色,如果有则使用自定义背景色
if (CustomBackgroundColor.HasValue)
{
GridBackgroundCover.Background = new SolidColorBrush(CustomBackgroundColor.Value);
}
else
{
GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(234, 235, 237));
}
WaterMarkTime.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
WaterMarkDate.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
BlackBoardWaterMark.Foreground = new SolidColorBrush(Color.FromRgb(22, 41, 36));
isUselightThemeColor = false;
}
else {
GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(22, 41, 36));
else
{
// 黑板模式下,检查是否有自定义背景色
if (CustomBackgroundColor.HasValue)
{
GridBackgroundCover.Background = new SolidColorBrush(CustomBackgroundColor.Value);
}
else
{
GridBackgroundCover.Background = new SolidColorBrush(Color.FromRgb(22, 41, 36));
}
WaterMarkTime.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
WaterMarkDate.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
BlackBoardWaterMark.Foreground = new SolidColorBrush(Color.FromRgb(234, 235, 237));
@@ -85,26 +111,32 @@ namespace Ink_Canvas {
}
}
if (currentMode == 0) {
if (currentMode == 0)
{
isUselightThemeColor = isDesktopUselightThemeColor;
inkColor = lastDesktopInkColor;
}
else {
else
{
inkColor = lastBoardInkColor;
}
double alpha = inkCanvas.DefaultDrawingAttributes.Color.A;
if (penType == 0) {
if (inkColor == 0) {
if (penType == 0)
{
if (inkColor == 0)
{
// Black
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 0, 0, 0);
}
else if (inkColor == 5) {
else if (inkColor == 5)
{
// White
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 255, 255, 255);
}
else if (isUselightThemeColor) {
else if (isUselightThemeColor)
{
if (inkColor == 1)
// Red
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 239, 68, 68);
@@ -127,7 +159,8 @@ namespace Ink_Canvas {
// Orange (亮色)
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 249, 115, 22);
}
else {
else
{
if (inkColor == 1)
// Red
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 220, 38, 38);
@@ -151,7 +184,8 @@ namespace Ink_Canvas {
inkCanvas.DefaultDrawingAttributes.Color = Color.FromArgb((byte)alpha, 234, 88, 12);
}
}
else if (penType == 1) {
else if (penType == 1)
{
if (highlighterColor == 100)
// Black
inkCanvas.DefaultDrawingAttributes.Color = Color.FromRgb(0, 0, 0);
@@ -184,7 +218,8 @@ namespace Ink_Canvas {
inkCanvas.DefaultDrawingAttributes.Color = Color.FromRgb(249, 115, 22);
}
if (isUselightThemeColor) {
if (isUselightThemeColor)
{
// 亮系
// 亮色的红色
BorderPenColorRed.Background = new SolidColorBrush(Color.FromRgb(239, 68, 68));
@@ -219,7 +254,8 @@ namespace Ink_Canvas {
ColorThemeSwitchTextBlock.Text = "暗系";
BoardColorThemeSwitchTextBlock.Text = "暗系";
}
else {
else
{
// 暗系
// 暗色的红色
BorderPenColorRed.Background = new SolidColorBrush(Color.FromRgb(220, 38, 38));
@@ -298,7 +334,8 @@ namespace Ink_Canvas {
BoardHighlighterPenViewboxBtnColorYellowContent.Visibility = Visibility.Collapsed;
BoardHighlighterPenViewboxBtnColorZincContent.Visibility = Visibility.Collapsed;
switch (inkColor) {
switch (inkColor)
{
case 0:
ViewboxBtnColorBlackContent.Visibility = Visibility.Visible;
BoardViewboxBtnColorBlackContent.Visibility = Visibility.Visible;
@@ -335,7 +372,8 @@ namespace Ink_Canvas {
break;
}
switch (highlighterColor) {
switch (highlighterColor)
{
case 100:
HighlighterPenViewboxBtnColorBlackContent.Visibility = Visibility.Visible;
BoardHighlighterPenViewboxBtnColorBlackContent.Visibility = Visibility.Visible;
@@ -377,20 +415,31 @@ namespace Ink_Canvas {
BoardHighlighterPenViewboxBtnColorOrangeContent.Visibility = Visibility.Visible;
break;
}
// 更新快捷调色盘选择指示器
if (penType == 0)
{
UpdateQuickColorPaletteIndicator(inkCanvas.DefaultDrawingAttributes.Color);
}
}
private void CheckLastColor(int inkColor, bool isHighlighter = false) {
if (isHighlighter == true) {
private void CheckLastColor(int inkColor, bool isHighlighter = false)
{
if (isHighlighter)
{
highlighterColor = inkColor;
}
else {
else
{
if (currentMode == 0) lastDesktopInkColor = inkColor;
else lastBoardInkColor = inkColor;
}
}
private async void CheckPenTypeUIState() {
if (penType == 0) {
private async void CheckPenTypeUIState()
{
if (penType == 0)
{
DefaultPenPropsPanel.Visibility = Visibility.Visible;
DefaultPenColorsPanel.Visibility = Visibility.Visible;
HighlighterPenColorsPanel.Visibility = Visibility.Collapsed;
@@ -426,7 +475,8 @@ namespace Ink_Canvas {
BoardHighlightPenTabButtonIndicator.Visibility = Visibility.Collapsed;
// PenPalette.Margin = new Thickness(-160, -200, -33, 32);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
@@ -437,7 +487,8 @@ namespace Ink_Canvas {
PenPalette.BeginAnimation(MarginProperty, marginAnimation);
});
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
@@ -455,7 +506,8 @@ namespace Ink_Canvas {
await Dispatcher.InvokeAsync(() => { BoardPenPaletteGrid.Margin = new Thickness(-160, -200, -33, 50); });
}
else if (penType == 1) {
else if (penType == 1)
{
DefaultPenPropsPanel.Visibility = Visibility.Collapsed;
DefaultPenColorsPanel.Visibility = Visibility.Collapsed;
HighlighterPenColorsPanel.Visibility = Visibility.Visible;
@@ -491,7 +543,8 @@ namespace Ink_Canvas {
BoardHighlightPenTabButtonIndicator.Visibility = Visibility.Visible;
// PenPalette.Margin = new Thickness(-160, -157, -33, 32);
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
@@ -502,7 +555,8 @@ namespace Ink_Canvas {
PenPalette.BeginAnimation(MarginProperty, marginAnimation);
});
await Dispatcher.InvokeAsync(() => {
await Dispatcher.InvokeAsync(() =>
{
var marginAnimation = new ThicknessAnimation
{
Duration = TimeSpan.FromSeconds(0.1),
@@ -521,7 +575,8 @@ namespace Ink_Canvas {
}
}
private void SwitchToDefaultPen(object sender, MouseButtonEventArgs e) {
private void SwitchToDefaultPen(object sender, MouseButtonEventArgs e)
{
penType = 0;
CheckPenTypeUIState();
CheckColorTheme();
@@ -531,7 +586,8 @@ namespace Ink_Canvas {
drawingAttributes.IsHighlighter = false;
}
private void SwitchToHighlighterPen(object sender, MouseButtonEventArgs e) {
private void SwitchToHighlighterPen(object sender, MouseButtonEventArgs e)
{
penType = 1;
CheckPenTypeUIState();
CheckColorTheme();
@@ -541,143 +597,145 @@ namespace Ink_Canvas {
drawingAttributes.IsHighlighter = true;
}
private void BtnColorBlack_Click(object sender, RoutedEventArgs e) {
private void BtnColorBlack_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(0);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorRed_Click(object sender, RoutedEventArgs e) {
private void BtnColorRed_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(1);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorGreen_Click(object sender, RoutedEventArgs e) {
private void BtnColorGreen_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(2);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorBlue_Click(object sender, RoutedEventArgs e) {
private void BtnColorBlue_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(3);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorYellow_Click(object sender, RoutedEventArgs e) {
private void BtnColorYellow_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(4);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorWhite_Click(object sender, RoutedEventArgs e) {
private void BtnColorWhite_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(5);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorPink_Click(object sender, RoutedEventArgs e) {
private void BtnColorPink_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(6);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorOrange_Click(object sender, RoutedEventArgs e) {
private void BtnColorOrange_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(8);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnColorTeal_Click(object sender, RoutedEventArgs e) {
private void BtnColorTeal_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(7);
forceEraser = false;
ColorSwitchCheck();
}
private void BtnHighlighterColorBlack_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorBlack_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(100, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorWhite_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorWhite_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(101, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorRed_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorRed_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(102, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorYellow_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorYellow_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(103, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorGreen_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorGreen_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(104, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorZinc_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorZinc_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(105, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorBlue_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorBlue_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(106, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorPurple_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorPurple_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(107, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorTeal_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorTeal_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(108, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private void BtnHighlighterColorOrange_Click(object sender, RoutedEventArgs e) {
private void BtnHighlighterColorOrange_Click(object sender, RoutedEventArgs e)
{
CheckLastColor(109, true);
penType = 1;
forceEraser = false;
CheckPenTypeUIState();
ColorSwitchCheck();
}
private Color StringToColor(string colorStr) {
private Color StringToColor(string colorStr)
{
var argb = new byte[4];
for (var i = 0; i < 4; i++) {
for (var i = 0; i < 4; i++)
{
var charArray = colorStr.Substring(i * 2 + 1, 2).ToCharArray();
var b1 = toByte(charArray[0]);
var b2 = toByte(charArray[1]);
@@ -687,7 +745,8 @@ namespace Ink_Canvas {
return Color.FromArgb(argb[0], argb[1], argb[2], argb[3]); //#FFFFFFFF
}
private static byte toByte(char c) {
private static byte toByte(char c)
{
var b = (byte)"0123456789ABCDEF".IndexOf(c);
return b;
}
@@ -0,0 +1,428 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
#region Image
private async void BtnImageInsert_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Image files (*.jpg; *.jpeg; *.png; *.bmp)|*.jpg;*.jpeg;*.png;*.bmp";
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName;
Image image = await CreateAndCompressImageAsync(filePath);
if (image != null)
{
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
image.Name = timestamp;
CenterAndScaleElement(image);
inkCanvas.Children.Add(image);
// 添加鼠标事件处理,使图片可以被选择
image.MouseDown += UIElement_MouseDown;
image.IsManipulationEnabled = true;
timeMachine.CommitElementInsertHistory(image);
}
}
}
private async Task<Image> CreateAndCompressImageAsync(string filePath)
{
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
string fileExtension = Path.GetExtension(filePath);
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
string newFilePath = Path.Combine(savePath, timestamp + fileExtension);
await Task.Run(() => File.Copy(filePath, newFilePath, true));
return await Dispatcher.InvokeAsync(() =>
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(newFilePath);
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
int width = bitmapImage.PixelWidth;
int height = bitmapImage.PixelHeight;
Image image = new Image();
// 设置拉伸模式为Fill,支持任意比例缩放
image.Stretch = Stretch.Fill;
if (isLoaded && Settings.Canvas.IsCompressPicturesUploaded && (width > 1920 || height > 1080))
{
double scaleX = 1920.0 / width;
double scaleY = 1080.0 / height;
double scale = Math.Min(scaleX, scaleY);
TransformedBitmap transformedBitmap = new TransformedBitmap(bitmapImage, new ScaleTransform(scale, scale));
image.Source = transformedBitmap;
image.Width = transformedBitmap.PixelWidth;
image.Height = transformedBitmap.PixelHeight;
}
else
{
image.Source = bitmapImage;
image.Width = width;
image.Height = height;
}
return image;
});
}
#endregion
#region Media
private async void BtnMediaInsert_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Media files (*.mp4; *.avi; *.wmv)|*.mp4;*.avi;*.wmv";
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName;
byte[] mediaBytes = await Task.Run(() => File.ReadAllBytes(filePath));
MediaElement mediaElement = await CreateMediaElementAsync(filePath);
if (mediaElement != null)
{
CenterAndScaleElement(mediaElement);
InkCanvas.SetLeft(mediaElement, 0);
InkCanvas.SetTop(mediaElement, 0);
inkCanvas.Children.Add(mediaElement);
// 添加鼠标事件处理,使媒体元素可以被选择
mediaElement.MouseDown += UIElement_MouseDown;
mediaElement.IsManipulationEnabled = true;
mediaElement.LoadedBehavior = MediaState.Manual;
mediaElement.UnloadedBehavior = MediaState.Manual;
mediaElement.Loaded += async (_, args) =>
{
mediaElement.Play();
await Task.Delay(100);
mediaElement.Pause();
};
timeMachine.CommitElementInsertHistory(mediaElement);
}
}
}
private async Task<MediaElement> CreateMediaElementAsync(string filePath)
{
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
return await Dispatcher.InvokeAsync(() =>
{
MediaElement mediaElement = new MediaElement();
mediaElement.Source = new Uri(filePath);
string timestamp = "media_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
mediaElement.Name = timestamp;
mediaElement.LoadedBehavior = MediaState.Manual;
mediaElement.UnloadedBehavior = MediaState.Manual;
mediaElement.Width = 256;
mediaElement.Height = 256;
string fileExtension = Path.GetExtension(filePath);
string newFilePath = Path.Combine(savePath, mediaElement.Name + fileExtension);
File.Copy(filePath, newFilePath, true);
mediaElement.Source = new Uri(newFilePath);
return mediaElement;
});
}
#endregion
#region Image Operations
/// <summary>
/// 旋转图片
/// </summary>
/// <param name="image">要旋转的图片</param>
/// <param name="angle">旋转角度(正数为顺时针,负数为逆时针)</param>
private void RotateImage(Image image, double angle)
{
if (image == null) return;
try
{
// 获取当前的变换
var transformGroup = image.RenderTransform as TransformGroup ?? new TransformGroup();
// 查找现有的旋转变换
RotateTransform rotateTransform = null;
foreach (Transform transform in transformGroup.Children)
{
if (transform is RotateTransform rt)
{
rotateTransform = rt;
break;
}
}
// 如果没有旋转变换,创建一个新的
if (rotateTransform == null)
{
rotateTransform = new RotateTransform();
transformGroup.Children.Add(rotateTransform);
}
// 设置旋转中心为图片中心
rotateTransform.CenterX = image.ActualWidth / 2;
rotateTransform.CenterY = image.ActualHeight / 2;
// 累加旋转角度
rotateTransform.Angle = (rotateTransform.Angle + angle) % 360;
// 应用变换
image.RenderTransform = transformGroup;
// 提交到时间机器以支持撤销
// 注意:旋转操作目前不支持撤销,因为需要更复杂的历史记录机制
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"旋转图片时发生错误: {ex.Message}");
}
}
/// <summary>
/// 克隆图片
/// </summary>
/// <param name="image">要克隆的图片</param>
private void CloneImage(Image image)
{
if (image == null) return;
try
{
// 创建图片的副本
var clonedImage = new Image
{
Source = image.Source,
Width = image.Width,
Height = image.Height,
Stretch = image.Stretch,
RenderTransform = image.RenderTransform?.Clone() as Transform
};
// 设置位置,稍微偏移以避免重叠
InkCanvas.SetLeft(clonedImage, InkCanvas.GetLeft(image) + 20);
InkCanvas.SetTop(clonedImage, InkCanvas.GetTop(image) + 20);
// 添加鼠标事件处理,使图片可以被选择
clonedImage.MouseDown += UIElement_MouseDown;
clonedImage.IsManipulationEnabled = true;
// 添加到画布
inkCanvas.Children.Add(clonedImage);
// 选择新克隆的图片
DeselectUIElement();
SelectUIElement(clonedImage);
// 提交到时间机器以支持撤销
timeMachine.CommitElementInsertHistory(clonedImage);
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"克隆图片时发生错误: {ex.Message}");
}
}
/// <summary>
/// 克隆图片到新页面
/// </summary>
/// <param name="image">要克隆的图片</param>
private void CloneImageToNewBoard(Image image)
{
if (image == null) return;
try
{
// 创建图片的副本
var clonedImage = new Image
{
Source = image.Source,
Width = image.Width,
Height = image.Height,
Stretch = image.Stretch,
RenderTransform = image.RenderTransform?.Clone() as Transform
};
// 设置位置,稍微偏移以避免重叠
InkCanvas.SetLeft(clonedImage, InkCanvas.GetLeft(image) + 20);
InkCanvas.SetTop(clonedImage, InkCanvas.GetTop(image) + 20);
// 添加鼠标事件处理,使图片可以被选择
clonedImage.MouseDown += UIElement_MouseDown;
clonedImage.IsManipulationEnabled = true;
// 创建新页面
BtnWhiteBoardAdd_Click(null, null);
// 添加到新页面的画布
inkCanvas.Children.Add(clonedImage);
// 选择新克隆的图片
DeselectUIElement();
SelectUIElement(clonedImage);
// 提交到时间机器以支持撤销
timeMachine.CommitElementInsertHistory(clonedImage);
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"克隆图片到新页面时发生错误: {ex.Message}");
}
}
/// <summary>
/// 缩放图片
/// </summary>
/// <param name="image">要缩放的图片</param>
/// <param name="scaleFactor">缩放因子(大于1为放大,小于1为缩小)</param>
private void ScaleImage(Image image, double scaleFactor)
{
if (image == null) return;
try
{
// 获取当前的变换
var transformGroup = image.RenderTransform as TransformGroup ?? new TransformGroup();
// 查找现有的缩放变换
ScaleTransform scaleTransform = null;
foreach (Transform transform in transformGroup.Children)
{
if (transform is ScaleTransform st)
{
scaleTransform = st;
break;
}
}
// 如果没有缩放变换,创建一个新的
if (scaleTransform == null)
{
scaleTransform = new ScaleTransform();
transformGroup.Children.Add(scaleTransform);
}
// 设置缩放中心为图片中心
scaleTransform.CenterX = image.ActualWidth / 2;
scaleTransform.CenterY = image.ActualHeight / 2;
// 应用缩放因子
scaleTransform.ScaleX *= scaleFactor;
scaleTransform.ScaleY *= scaleFactor;
// 应用变换
image.RenderTransform = transformGroup;
// 提交到时间机器以支持撤销
// 注意:缩放操作目前不支持撤销,因为需要更复杂的历史记录机制
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"缩放图片时发生错误: {ex.Message}");
}
}
/// <summary>
/// 删除图片
/// </summary>
/// <param name="image">要删除的图片</param>
private void DeleteImage(Image image)
{
if (image == null) return;
try
{
// 从画布中移除图片
if (inkCanvas.Children.Contains(image))
{
inkCanvas.Children.Remove(image);
// 取消选择
DeselectUIElement();
// 提交到时间机器以支持撤销
timeMachine.CommitElementRemoveHistory(image);
}
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"删除图片时发生错误: {ex.Message}");
}
}
#endregion
private void CenterAndScaleElement(FrameworkElement element)
{
double maxWidth = SystemParameters.PrimaryScreenWidth / 2;
double maxHeight = SystemParameters.PrimaryScreenHeight / 2;
double scaleX = maxWidth / element.Width;
double scaleY = maxHeight / element.Height;
double scale = Math.Min(scaleX, scaleY);
// 直接设置元素的大小,而不使用RenderTransform
double newWidth = element.Width * scale;
double newHeight = element.Height * scale;
element.Width = newWidth;
element.Height = newHeight;
// 计算居中位置
double canvasWidth = inkCanvas.ActualWidth;
double canvasHeight = inkCanvas.ActualHeight;
double centerX = (canvasWidth - newWidth) / 2;
double centerY = (canvasHeight - newHeight) / 2;
// 直接设置位置,而不使用RenderTransform
InkCanvas.SetLeft(element, centerX);
InkCanvas.SetTop(element, centerY);
// 清除任何现有的RenderTransform
element.RenderTransform = Transform.Identity;
}
}
}
+869
View File
@@ -0,0 +1,869 @@
using Ink_Canvas.Helpers;
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
// 新橡皮擦系统的核心变量
public bool isUsingAdvancedEraser;
private IncrementalStrokeHitTester advancedHitTester;
// 橡皮擦配置
public double currentEraserSize = 64;
public bool isCurrentEraserCircle;
public bool isUsingStrokeEraser;
// 视觉反馈相关
private Matrix eraserTransformMatrix;
private Point lastEraserPosition;
private bool isEraserVisible;
// 性能优化相关
private DateTime lastEraserUpdate = DateTime.Now;
private const double ERASER_UPDATE_INTERVAL = 16.67; // 约60FPS
// 锁定笔画的GUID(如果不存在则创建一个默认值)
private static readonly Guid IsLockGuid = new Guid("12345678-1234-1234-1234-123456789ABC");
// 橡皮擦视觉反馈控件
private DrawingVisual eraserVisual = new DrawingVisual();
private VisualCanvas eraserOverlayCanvas = null;
private Border eraserVisualBorder; // 用于显示橡皮擦视觉反馈的Border
// 兼容性属性:模拟原有的EraserOverlay_DrawingVisual
private VisualCanvas EraserOverlay_DrawingVisual => eraserOverlayCanvas;
// 兼容性保持
[Obsolete("使用 isUsingAdvancedEraser 替代")]
public bool isUsingGeometryEraser
{
get => isUsingAdvancedEraser;
set => isUsingAdvancedEraser = value;
}
[Obsolete("使用 currentEraserSize 替代")]
public double eraserWidth
{
get => currentEraserSize;
set => currentEraserSize = value;
}
[Obsolete("使用 isCurrentEraserCircle 替代")]
public bool isEraserCircleShape
{
get => isCurrentEraserCircle;
set => isCurrentEraserCircle = value;
}
[Obsolete("使用 isUsingStrokeEraser 替代")]
public bool isUsingStrokesEraser
{
get => isUsingStrokeEraser;
set => isUsingStrokeEraser = value;
}
[Obsolete("使用 eraserTransformMatrix 替代")]
private Matrix scaleMatrix
{
get => eraserTransformMatrix;
set => eraserTransformMatrix = value;
}
/// <summary>
/// 新橡皮擦覆盖层加载事件处理
/// </summary>
private void EraserOverlay_Loaded(object sender, RoutedEventArgs e)
{
var border = (Border)sender;
// 初始化覆盖层
InitializeEraserOverlay(border);
Trace.WriteLine("Advanced Eraser: Overlay loaded and initialized");
}
/// <summary>
/// 开始高级橡皮擦操作
/// </summary>
private void StartAdvancedEraserOperation(object sender)
{
if (isUsingAdvancedEraser) return;
// 设置操作状态
isUsingAdvancedEraser = true;
isEraserVisible = true;
// 更新橡皮擦尺寸
UpdateEraserSize();
// 获取inkCanvas引用
var inkCanvas = FindName("inkCanvas") as InkCanvas;
if (inkCanvas == null) return;
// 根据橡皮擦形状创建碰撞检测器
StylusShape eraserShape = CreateEraserShape();
advancedHitTester = inkCanvas.Strokes.GetIncrementalStrokeHitTester(eraserShape);
advancedHitTester.StrokeHit += OnAdvancedEraserStrokeHit;
// 初始化变换矩阵
InitializeEraserTransform();
}
/// <summary>
/// 创建橡皮擦形状
/// </summary>
private StylusShape CreateEraserShape()
{
if (isCurrentEraserCircle)
{
return new EllipseStylusShape(currentEraserSize, currentEraserSize);
}
// 矩形橡皮擦,使用与原来相同的逻辑
return new RectangleStylusShape(currentEraserSize, currentEraserSize / 0.6);
}
/// <summary>
/// 初始化橡皮擦变换矩阵
/// </summary>
private void InitializeEraserTransform()
{
eraserTransformMatrix = new Matrix();
if (isCurrentEraserCircle)
{
// 圆形橡皮擦:等比例缩放
var scale = currentEraserSize / 56.0; // 基于56x56的基准尺寸
eraserTransformMatrix.ScaleAt(scale, scale, 0, 0);
}
else
{
// 矩形橡皮擦:保持传统比例
var scaleX = currentEraserSize / 38.0;
var scaleY = (currentEraserSize * 56 / 38) / 56.0;
eraserTransformMatrix.ScaleAt(scaleX, scaleY, 0, 0);
}
}
/// <summary>
/// 更新橡皮擦尺寸
/// </summary>
private void UpdateEraserSize()
{
// 使用与原来相同的逻辑计算橡皮擦尺寸
double k = 1.0;
switch (Settings.Canvas.EraserSize)
{
case 0: k = Settings.Canvas.EraserShapeType == 0 ? 0.5 : 0.7; break;
case 1: k = Settings.Canvas.EraserShapeType == 0 ? 0.8 : 0.9; break;
case 2: k = 1.0; break;
case 3: k = Settings.Canvas.EraserShapeType == 0 ? 1.25 : 1.2; break;
case 4: k = Settings.Canvas.EraserShapeType == 0 ? 1.5 : 1.3; break;
}
// 更新形状类型
isCurrentEraserCircle = (Settings.Canvas.EraserShapeType == 0);
// 根据形状类型设置尺寸
if (isCurrentEraserCircle)
{
currentEraserSize = k * 90; // 圆形橡皮擦
}
else
{
currentEraserSize = k * 90 * 0.6; // 矩形橡皮擦宽度
}
}
/// <summary>
/// 结束高级橡皮擦操作
/// </summary>
private void EndAdvancedEraserOperation(object sender)
{
if (!isUsingAdvancedEraser) return;
// 重置操作状态
isUsingAdvancedEraser = false;
isEraserVisible = false;
// 释放鼠标捕获
if (sender is Border border)
{
border.ReleaseMouseCapture();
}
// 隐藏橡皮擦视觉反馈
HideEraserFeedback();
// 结束碰撞检测
if (advancedHitTester != null)
{
advancedHitTester.EndHitTesting();
advancedHitTester = null;
}
// 提交橡皮擦历史记录
CommitEraserHistory();
}
/// <summary>
/// 隐藏橡皮擦视觉反馈
/// </summary>
private void HideEraserFeedback()
{
try
{
if (eraserVisualBorder != null)
{
eraserVisualBorder.Visibility = Visibility.Collapsed;
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error hiding feedback - {ex.Message}");
}
}
/// <summary>
/// 提交橡皮擦历史记录
/// </summary>
private void CommitEraserHistory()
{
try
{
if (ReplacedStroke != null || AddedStroke != null)
{
timeMachine.CommitStrokeEraseHistory(ReplacedStroke, AddedStroke);
AddedStroke = null;
ReplacedStroke = null;
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error committing history - {ex.Message}");
}
}
/// <summary>
/// 高级橡皮擦笔画碰撞事件处理
/// </summary>
private void OnAdvancedEraserStrokeHit(object sender, StrokeHitEventArgs args)
{
try
{
var inkCanvas = FindName("inkCanvas") as InkCanvas;
if (inkCanvas == null) return;
var eraseResult = args.GetPointEraseResults();
var strokeToReplace = new StrokeCollection { args.HitStroke };
// 过滤锁定的笔画
var filteredToReplace = strokeToReplace.Where(stroke => !stroke.ContainsPropertyData(IsLockGuid));
var filteredToReplaceArray = filteredToReplace as Stroke[] ?? filteredToReplace.ToArray();
if (!filteredToReplaceArray.Any()) return;
var filteredResult = eraseResult.Where(stroke => !stroke.ContainsPropertyData(IsLockGuid));
var filteredResultArray = filteredResult as Stroke[] ?? filteredResult.ToArray();
// 执行笔画替换或删除
if (filteredResultArray.Any())
{
inkCanvas.Strokes.Replace(
new StrokeCollection(filteredToReplaceArray),
new StrokeCollection(filteredResultArray)
);
}
else
{
inkCanvas.Strokes.Remove(new StrokeCollection(filteredToReplaceArray));
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error in stroke hit - {ex.Message}");
}
}
/// <summary>
/// 更新高级橡皮擦位置
/// </summary>
private void UpdateAdvancedEraserPosition(object sender, Point position)
{
// 移除isUsingAdvancedEraser检查,让视觉反馈始终更新
// if (!isUsingAdvancedEraser) return;
// 性能优化:限制更新频率
var now = DateTime.Now;
if ((now - lastEraserUpdate).TotalMilliseconds < ERASER_UPDATE_INTERVAL)
{
return;
}
lastEraserUpdate = now;
// 更新位置
lastEraserPosition = position;
// 更新视觉反馈(始终执行)
UpdateEraserVisualFeedback(position);
// 只有在实际使用橡皮擦时才处理擦除
if (isUsingAdvancedEraser)
{
// 处理不同的橡皮擦模式
if (isUsingStrokeEraser)
{
ProcessStrokeEraserAtPosition(position);
}
else
{
ProcessGeometryEraserAtPosition(position);
}
}
}
/// <summary>
/// 在指定位置处理笔画橡皮擦
/// </summary>
private void ProcessStrokeEraserAtPosition(Point position)
{
try
{
var inkCanvas = FindName("inkCanvas") as InkCanvas;
if (inkCanvas == null) return;
var hitStrokes = inkCanvas.Strokes.HitTest(position)
.Where(stroke => !stroke.ContainsPropertyData(IsLockGuid));
var strokesArray = hitStrokes as Stroke[] ?? hitStrokes.ToArray();
if (strokesArray.Any())
{
inkCanvas.Strokes.Remove(new StrokeCollection(strokesArray));
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error in stroke eraser - {ex.Message}");
}
}
/// <summary>
/// 在指定位置处理几何橡皮擦
/// </summary>
private void ProcessGeometryEraserAtPosition(Point position)
{
try
{
if (advancedHitTester != null)
{
advancedHitTester.AddPoint(position);
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error in geometry eraser - {ex.Message}");
}
}
/// <summary>
/// 更新橡皮擦视觉反馈
/// </summary>
private void UpdateEraserVisualFeedback(Point position)
{
try
{
// 获取或创建橡皮擦视觉反馈Border
if (eraserVisualBorder == null)
{
eraserVisualBorder = new Border
{
Background = new SolidColorBrush(Colors.Transparent),
BorderBrush = new SolidColorBrush(Colors.Transparent),
BorderThickness = new Thickness(0),
IsHitTestVisible = false,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Opacity = 1
};
Panel.SetZIndex(eraserVisualBorder, 1001);
// 将Border添加到InkCanvasGridForInkReplay中
var inkCanvasGrid = FindName("InkCanvasGridForInkReplay") as Grid;
if (inkCanvasGrid != null)
{
inkCanvasGrid.Children.Add(eraserVisualBorder);
Trace.WriteLine("Advanced Eraser: Visual feedback border added to grid");
}
else
{
Trace.WriteLine("Advanced Eraser: Failed to find InkCanvasGridForInkReplay");
return; // 如果找不到Grid,直接返回
}
}
if (eraserVisualBorder != null)
{
// 创建橡皮擦视觉反馈
var eraserImage = CreateEraserVisualImage();
// 清除Border的内容并添加新的图像
eraserVisualBorder.Child = eraserImage;
// 更新橡皮擦位置和大小
if (isCurrentEraserCircle)
{
var radius = currentEraserSize / 2;
eraserVisualBorder.Width = currentEraserSize;
eraserVisualBorder.Height = currentEraserSize;
// 使用Margin来定位,因为Border在Grid中
eraserVisualBorder.Margin = new Thickness(
position.X - radius,
position.Y - radius,
0, 0);
}
else
{
// 矩形橡皮擦,使用与原来相同的逻辑
var height = currentEraserSize / 0.6;
eraserVisualBorder.Width = currentEraserSize;
eraserVisualBorder.Height = height;
// 使用Margin来定位,因为Border在Grid中
eraserVisualBorder.Margin = new Thickness(
position.X - currentEraserSize / 2,
position.Y - height / 2,
0, 0);
}
eraserVisualBorder.Visibility = Visibility.Visible;
Trace.WriteLine($"Advanced Eraser: Visual feedback updated to ({position.X:F1}, {position.Y:F1})");
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error updating visual feedback - {ex.Message}");
}
}
/// <summary>
/// 创建橡皮擦视觉图像
/// </summary>
private Image CreateEraserVisualImage()
{
try
{
// 根据橡皮擦形状选择对应的DrawingGroup资源
string resourceKey = isCurrentEraserCircle ? "EraserCircleDrawingGroup" : "EraserDrawingGroup";
// 尝试从资源字典中获取DrawingGroup
var drawingGroup = TryFindResource(resourceKey) as DrawingGroup;
if (drawingGroup == null)
{
// 如果找不到资源,创建默认的橡皮擦图像
return CreateDefaultEraserImage();
}
// 创建变换后的DrawingGroup
var transformedGroup = new DrawingGroup();
transformedGroup.Children.Add(drawingGroup);
// 应用缩放变换
var transform = new ScaleTransform();
if (isCurrentEraserCircle)
{
var scale = currentEraserSize / 56.0; // 基于56x56的基准尺寸
transform.ScaleX = scale;
transform.ScaleY = scale;
}
else
{
var scaleX = currentEraserSize / 38.0;
var scaleY = (currentEraserSize / 0.6) / 56.0;
transform.ScaleX = scaleX;
transform.ScaleY = scaleY;
}
transformedGroup.Transform = transform;
// 创建DrawingImage
var drawingImage = new DrawingImage(transformedGroup);
// 创建Image控件
var image = new Image
{
Source = drawingImage,
Stretch = Stretch.None
};
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
return image;
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error creating eraser visual image - {ex.Message}");
return CreateDefaultEraserImage();
}
}
/// <summary>
/// 创建默认的橡皮擦图像(当资源不可用时)
/// </summary>
private Image CreateDefaultEraserImage()
{
try
{
// 创建一个简单的几何图形作为默认橡皮擦
Geometry geometry;
if (isCurrentEraserCircle)
{
geometry = new EllipseGeometry(new Point(28, 28), 28, 28);
}
else
{
geometry = new RectangleGeometry(new Rect(0, 0, 38, 56));
}
var brush = new SolidColorBrush(Colors.LightGray);
var pen = new Pen(new SolidColorBrush(Colors.DarkGray), 1);
var geometryDrawing = new GeometryDrawing(brush, pen, geometry);
var drawingGroup = new DrawingGroup();
drawingGroup.Children.Add(geometryDrawing);
// 应用缩放变换
var transform = new ScaleTransform();
if (isCurrentEraserCircle)
{
var scale = currentEraserSize / 56.0;
transform.ScaleX = scale;
transform.ScaleY = scale;
}
else
{
var scaleX = currentEraserSize / 38.0;
var scaleY = (currentEraserSize / 0.6) / 56.0;
transform.ScaleX = scaleX;
transform.ScaleY = scaleY;
}
drawingGroup.Transform = transform;
var drawingImage = new DrawingImage(drawingGroup);
var image = new Image
{
Source = drawingImage,
Stretch = Stretch.None
};
return image;
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error creating default eraser image - {ex.Message}");
return null;
}
}
/// <summary>
/// 兼容性方法:旧版橡皮擦几何碰撞处理
/// </summary>
[Obsolete("使用 OnAdvancedEraserStrokeHit 替代")]
private void EraserGeometry_StrokeHit(object sender, StrokeHitEventArgs args)
{
OnAdvancedEraserStrokeHit(sender, args);
}
/// <summary>
/// 兼容性方法:旧版橡皮擦移动处理
/// </summary>
[Obsolete("使用 UpdateAdvancedEraserPosition 替代")]
private void EraserOverlay_PointerMove(object sender, Point pt)
{
UpdateAdvancedEraserPosition(sender, pt);
}
/// <summary>
/// 兼容性方法:旧版橡皮擦按下处理
/// </summary>
[Obsolete("使用 StartAdvancedEraserOperation 替代")]
private void EraserOverlay_PointerDown(object sender)
{
StartAdvancedEraserOperation(sender);
}
/// <summary>
/// 兼容性方法:旧版橡皮擦抬起处理
/// </summary>
[Obsolete("使用 EndAdvancedEraserOperation 替代")]
private void EraserOverlay_PointerUp(object sender)
{
EndAdvancedEraserOperation(sender);
}
/// <summary>
/// 获取当前橡皮擦状态信息(用于调试)
/// </summary>
public string GetEraserStatusInfo()
{
return "Advanced Eraser Status:\n" +
$"- Active: {isUsingAdvancedEraser}\n" +
$"- Size: {currentEraserSize:F1}\n" +
$"- Shape: {(isCurrentEraserCircle ? "Circle" : "Rectangle")}\n" +
$"- Mode: {(isUsingStrokeEraser ? "Stroke" : "Geometry")}\n" +
$"- Visible: {isEraserVisible}\n" +
$"- Last Position: ({lastEraserPosition.X:F1}, {lastEraserPosition.Y:F1})";
}
/// <summary>
/// 重置橡皮擦状态
/// </summary>
public void ResetEraserState()
{
isUsingAdvancedEraser = false;
isEraserVisible = false;
lastEraserPosition = new Point();
if (advancedHitTester != null)
{
advancedHitTester.EndHitTesting();
advancedHitTester = null;
}
HideEraserFeedback();
// 清理视觉反馈Border
if (eraserVisualBorder != null)
{
var inkCanvasGrid = FindName("InkCanvasGridForInkReplay") as Grid;
if (inkCanvasGrid != null)
{
inkCanvasGrid.Children.Remove(eraserVisualBorder);
}
eraserVisualBorder = null;
}
}
/// <summary>
/// 应用高级橡皮擦形状到InkCanvas
/// </summary>
public void ApplyAdvancedEraserShape()
{
try
{
var inkCanvas = FindName("inkCanvas") as InkCanvas;
if (inkCanvas == null) return;
// 更新橡皮擦尺寸和形状
UpdateEraserSize();
// 创建橡皮擦形状
StylusShape eraserShape = CreateEraserShape();
// 应用到InkCanvas
inkCanvas.EraserShape = eraserShape;
Trace.WriteLine($"Advanced Eraser: Applied shape - Size: {currentEraserSize}, Circle: {isCurrentEraserCircle}");
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error applying shape - {ex.Message}");
// 回退到传统方法
try
{
ApplyCurrentEraserShape();
}
catch (Exception fallbackEx)
{
Trace.WriteLine($"Advanced Eraser: Fallback also failed - {fallbackEx.Message}");
}
}
}
/// <summary>
/// 启用高级橡皮擦系统
/// </summary>
public void EnableAdvancedEraserSystem()
{
try
{
// 获取橡皮擦覆盖层
var eraserOverlay = FindName("AdvancedEraserOverlay") as Border;
if (eraserOverlay != null)
{
// 启用覆盖层的交互
eraserOverlay.IsHitTestVisible = true;
// 确保覆盖层在橡皮擦模式下启用
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
eraserOverlay.IsHitTestVisible = true;
Trace.WriteLine("Advanced Eraser: Overlay enabled for eraser mode");
}
// 设置覆盖层的大小以覆盖整个InkCanvas
var inkCanvasControl = FindName("inkCanvas") as InkCanvas;
if (inkCanvasControl != null)
{
eraserOverlay.Width = inkCanvasControl.ActualWidth;
eraserOverlay.Height = inkCanvasControl.ActualHeight;
Trace.WriteLine($"Advanced Eraser: Overlay size set to {eraserOverlay.Width}x{eraserOverlay.Height}");
}
Trace.WriteLine("Advanced Eraser: System enabled successfully");
}
else
{
Trace.WriteLine("Advanced Eraser: Failed to find eraser overlay");
}
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error enabling system - {ex.Message}");
}
}
/// <summary>
/// 初始化橡皮擦覆盖层
/// </summary>
private void InitializeEraserOverlay(Border overlay)
{
try
{
// 设置覆盖层的基本属性
overlay.Background = new SolidColorBrush(Colors.Transparent);
overlay.IsHitTestVisible = false; // 默认禁用,只在橡皮擦模式下启用
// 绑定事件处理
overlay.MouseDown += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
overlay.CaptureMouse();
StartAdvancedEraserOperation(sender);
}
};
overlay.MouseUp += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
overlay.ReleaseMouseCapture();
EndAdvancedEraserOperation(sender);
}
};
overlay.MouseMove += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
var position = e.GetPosition((UIElement)FindName("inkCanvas"));
Trace.WriteLine($"Advanced Eraser: Mouse move event triggered at ({position.X:F1}, {position.Y:F1})");
UpdateAdvancedEraserPosition(sender, position);
}
else
{
Trace.WriteLine($"Advanced Eraser: Mouse move ignored - not in eraser mode, current mode: {inkCanvas.EditingMode}");
}
};
// 触控笔事件
overlay.StylusDown += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
e.Handled = true;
if (e.StylusDevice.TabletDevice.Type == TabletDeviceType.Stylus)
{
overlay.CaptureStylus();
}
StartAdvancedEraserOperation(sender);
}
};
overlay.StylusUp += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
e.Handled = true;
if (e.StylusDevice.TabletDevice.Type == TabletDeviceType.Stylus)
{
overlay.ReleaseStylusCapture();
}
EndAdvancedEraserOperation(sender);
}
};
overlay.StylusMove += (sender, e) =>
{
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
e.Handled = true;
var position = e.GetPosition((UIElement)FindName("inkCanvas"));
UpdateAdvancedEraserPosition(sender, position);
Trace.WriteLine($"Advanced Eraser: Stylus move at ({position.X:F1}, {position.Y:F1})");
}
};
Trace.WriteLine("Advanced Eraser: Overlay initialized successfully");
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error initializing overlay - {ex.Message}");
}
}
/// <summary>
/// 禁用高级橡皮擦系统
/// </summary>
public void DisableAdvancedEraserSystem()
{
try
{
// 重置橡皮擦状态
ResetEraserState();
// 获取橡皮擦覆盖层并禁用
var eraserOverlay = FindName("AdvancedEraserOverlay") as Border;
if (eraserOverlay != null)
{
eraserOverlay.IsHitTestVisible = false;
}
// 确保视觉反馈被隐藏
HideEraserFeedback();
Trace.WriteLine("Advanced Eraser: System disabled successfully");
}
catch (Exception ex)
{
Trace.WriteLine($"Advanced Eraser: Error disabling system - {ex.Message}");
}
}
/// <summary>
/// 切换橡皮擦形状(圆形/矩形)
/// </summary>
public void ToggleEraserShape()
{
isCurrentEraserCircle = !isCurrentEraserCircle;
// 更新设置
Settings.Canvas.EraserShapeType = isCurrentEraserCircle ? 0 : 1;
// 应用新形状
ApplyAdvancedEraserShape();
Trace.WriteLine($"Advanced Eraser: Toggled to {(isCurrentEraserCircle ? "Circle" : "Rectangle")}");
}
}
}
+36
View File
@@ -0,0 +1,36 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingGroup x:Key="EraserDrawingGroup" ClipGeometry="M0,0 V56 H38 V0 H0 Z">
<GeometryDrawing Brush="#FFF2EEEB" Geometry="F1 M38,56z M0,0z M0,4C0,1.79086,1.79086,0,4,0L34,0C36.2091,0,38,1.79086,38,4L38,52C38,54.2091,36.2091,56,34,56L4,56C1.79086,56,0,54.2091,0,52L0,4z" />
<GeometryDrawing Brush="#FFCDCDCD" Geometry="F0 M38,56z M0,0z M34,1L4,1C2.34315,1,1,2.34315,1,4L1,52C1,53.6569,2.34315,55,4,55L34,55C35.6569,55,37,53.6569,37,52L37,4C37,2.34315,35.6569,1,34,1z M4,0C1.79086,0,0,1.79086,0,4L0,52C0,54.2091,1.79086,56,4,56L34,56C36.2091,56,38,54.2091,38,52L38,4C38,1.79086,36.2091,0,34,0L4,0z" />
<GeometryDrawing Brush="#FFD1CFCD" Geometry="F1 M38,56z M0,0z M12,19.5C12,18.1193,13.1193,17,14.5,17L14.5,17C15.8807,17,17,18.1193,17,19.5L17,36.5C17,37.8807,15.8807,39,14.5,39L14.5,39C13.1193,39,12,37.8807,12,36.5L12,19.5z" />
<GeometryDrawing Geometry="F0 M38,56z M0,0z M11.5,19.5C11.5,17.8431 12.8431,16.5 14.5,16.5 16.1569,16.5 17.5,17.8431 17.5,19.5L17.5,36.5C17.5,38.1569 16.1569,39.5 14.5,39.5 12.8431,39.5 11.5,38.1569 11.5,36.5L11.5,19.5z M14.5,17.5C13.3954,17.5,12.5,18.3954,12.5,19.5L12.5,36.5C12.5,37.6046 13.3954,38.5 14.5,38.5 15.6046,38.5 16.5,37.6046 16.5,36.5L16.5,19.5C16.5,18.3954,15.6046,17.5,14.5,17.5z">
<GeometryDrawing.Brush>
<SolidColorBrush Color="#FF6F6F6F" Opacity="0.25" />
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing Brush="#FFD1CFCD" Geometry="F1 M38,56z M0,0z M21,19.5C21,18.1193,22.1193,17,23.5,17L23.5,17C24.8807,17,26,18.1193,26,19.5L26,36.5C26,37.8807,24.8807,39,23.5,39L23.5,39C22.1193,39,21,37.8807,21,36.5L21,19.5z" />
<GeometryDrawing Geometry="F0 M38,56z M0,0z M20.5,19.5C20.5,17.8431 21.8431,16.5 23.5,16.5 25.1569,16.5 26.5,17.8431 26.5,19.5L26.5,36.5C26.5,38.1569 25.1569,39.5 23.5,39.5 21.8431,39.5 20.5,38.1569 20.5,36.5L20.5,19.5z M23.5,17.5C22.3954,17.5,21.5,18.3954,21.5,19.5L21.5,36.5C21.5,37.6046 22.3954,38.5 23.5,38.5 24.6046,38.5 25.5,37.6046 25.5,36.5L25.5,19.5C25.5,18.3954,24.6046,17.5,23.5,17.5z">
<GeometryDrawing.Brush>
<SolidColorBrush Color="#FF6F6F6F" Opacity="0.25" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
<DrawingGroup x:Key="EraserCircleDrawingGroup" ClipGeometry="M0,0 V56 H56 V0 H0 Z">
<GeometryDrawing Brush="#FFF2EEEB" Geometry="F1 M56,56z M0,0z M0,28C0,12.536,12.536,0,28,0L28,0C43.464,0,56,12.536,56,28L56,28C56,43.464,43.464,56,28,56L28,56C12.536,56,0,43.464,0,28L0,28z" />
<GeometryDrawing Brush="#FFCDCDCD" Geometry="F0 M56,56z M0,0z M1,28C1,42.9117 13.0883,55 28,55 42.9117,55 55,42.9117 55,28 55,13.0883 42.9117,1 28,1 13.0883,1 1,13.0883 1,28z M28,0C12.536,0 0,12.536 0,28 0,43.464 12.536,56 28,56 43.464,56 56,43.464 56,28 56,12.536 43.464,0 28,0z" />
<GeometryDrawing Brush="#FFD1CFCD" Geometry="F1 M56,56z M0,0z M21,19.5C21,18.1193,22.1193,17,23.5,17L23.5,17C24.8807,17,26,18.1193,26,19.5L26,36.5C26,37.8807,24.8807,39,23.5,39L23.5,39C22.1193,39,21,37.8807,21,36.5L21,19.5z" />
<GeometryDrawing Geometry="F0 M56,56z M0,0z M20.5,19.5C20.5,17.8431 21.8431,16.5 23.5,16.5 25.1569,16.5 26.5,17.8431 26.5,19.5L26.5,36.5C26.5,38.1569 25.1569,39.5 23.5,39.5 21.8431,39.5 20.5,38.1569 20.5,36.5L20.5,19.5z M23.5,17.5C22.3954,17.5,21.5,18.3954,21.5,19.5L21.5,36.5C21.5,37.6046 22.3954,38.5 23.5,38.5 24.6046,38.5 25.5,37.6046 25.5,36.5L25.5,19.5C25.5,18.3954,24.6046,17.5,23.5,17.5z">
<GeometryDrawing.Brush>
<SolidColorBrush Color="#FF6F6F6F" Opacity="0.25" />
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing Brush="#FFD1CFCD" Geometry="F1 M56,56z M0,0z M30,19.5C30,18.1193,31.1193,17,32.5,17L32.5,17C33.8807,17,35,18.1193,35,19.5L35,36.5C35,37.8807,33.8807,39,32.5,39L32.5,39C31.1193,39,30,37.8807,30,36.5L30,19.5z" />
<GeometryDrawing Geometry="F0 M56,56z M0,0z M29.5,19.5C29.5,17.8431 30.8431,16.5 32.5,16.5 34.1569,16.5 35.5,17.8431 35.5,19.5L35.5,36.5C35.5,38.1569 34.1569,39.5 32.5,39.5 30.8431,39.5 29.5,38.1569 29.5,36.5L29.5,19.5z M32.5,17.5C31.3954,17.5,30.5,18.3954,30.5,19.5L30.5,36.5C30.5,37.6046 31.3954,38.5 32.5,38.5 33.6046,38.5 34.5,37.6046 34.5,36.5L34.5,19.5C34.5,18.3954,33.6046,17.5,32.5,17.5z">
<GeometryDrawing.Brush>
<SolidColorBrush Color="#FF6F6F6F" Opacity="0.25" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</ResourceDictionary>
File diff suppressed because it is too large Load Diff
+42 -21
View File
@@ -1,16 +1,20 @@
using System.Windows;
using System.Windows.Input;
namespace Ink_Canvas {
public partial class MainWindow : Window {
private void Window_MouseWheel(object sender, MouseWheelEventArgs e) {
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (StackPanelPPTControls.Visibility != Visibility.Visible || currentMode != 0) return;
if (e.Delta >= 120)
BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
else if (e.Delta <= -120) BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
}
private void Main_Grid_PreviewKeyDown(object sender, KeyEventArgs e) {
private void Main_Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (StackPanelPPTControls.Visibility != Visibility.Visible || currentMode != 0) return;
if (e.Key == Key.Down || e.Key == Key.PageDown || e.Key == Key.Right || e.Key == Key.N ||
@@ -19,53 +23,66 @@ namespace Ink_Canvas {
BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
}
private void Window_KeyDown(object sender, KeyEventArgs e) {
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape) KeyExit(null, null);
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void HotKey_Undo(object sender, ExecutedRoutedEventArgs e) {
try {
private void HotKey_Undo(object sender, ExecutedRoutedEventArgs e)
{
try
{
SymbolIconUndo_MouseUp(lastBorderMouseDownObject, null);
}
catch { }
}
private void HotKey_Redo(object sender, ExecutedRoutedEventArgs e) {
try {
private void HotKey_Redo(object sender, ExecutedRoutedEventArgs e)
{
try
{
SymbolIconRedo_MouseUp(lastBorderMouseDownObject, null);
}
catch { }
}
private void HotKey_Clear(object sender, ExecutedRoutedEventArgs e) {
private void HotKey_Clear(object sender, ExecutedRoutedEventArgs e)
{
SymbolIconDelete_MouseUp(lastBorderMouseDownObject, null);
}
private void KeyExit(object sender, ExecutedRoutedEventArgs e) {
private void KeyExit(object sender, ExecutedRoutedEventArgs e)
{
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) BtnPPTSlideShowEnd_Click(BtnPPTSlideShowEnd, null);
}
private void KeyChangeToDrawTool(object sender, ExecutedRoutedEventArgs e) {
private void KeyChangeToDrawTool(object sender, ExecutedRoutedEventArgs e)
{
PenIcon_Click(lastBorderMouseDownObject, null);
}
private void KeyChangeToQuitDrawTool(object sender, ExecutedRoutedEventArgs e) {
private void KeyChangeToQuitDrawTool(object sender, ExecutedRoutedEventArgs e)
{
if (currentMode != 0) ImageBlackboard_MouseUp(lastBorderMouseDownObject, null);
CursorIcon_Click(lastBorderMouseDownObject, null);
}
private void KeyChangeToSelect(object sender, ExecutedRoutedEventArgs e) {
private void KeyChangeToSelect(object sender, ExecutedRoutedEventArgs e)
{
if (StackPanelCanvasControls.Visibility == Visibility.Visible)
SymbolIconSelect_MouseUp(lastBorderMouseDownObject, null);
}
private void KeyChangeToEraser(object sender, ExecutedRoutedEventArgs e) {
if (StackPanelCanvasControls.Visibility == Visibility.Visible) {
private void KeyChangeToEraser(object sender, ExecutedRoutedEventArgs e)
{
if (StackPanelCanvasControls.Visibility == Visibility.Visible)
{
if (Eraser_Icon.Background != null)
EraserIconByStrokes_Click(lastBorderMouseDownObject, null);
else
@@ -73,19 +90,23 @@ namespace Ink_Canvas {
}
}
private void KeyChangeToBoard(object sender, ExecutedRoutedEventArgs e) {
private void KeyChangeToBoard(object sender, ExecutedRoutedEventArgs e)
{
ImageBlackboard_MouseUp(lastBorderMouseDownObject, null);
}
private void KeyCapture(object sender, ExecutedRoutedEventArgs e) {
private void KeyCapture(object sender, ExecutedRoutedEventArgs e)
{
SaveScreenShotToDesktop();
}
private void KeyDrawLine(object sender, ExecutedRoutedEventArgs e) {
private void KeyDrawLine(object sender, ExecutedRoutedEventArgs e)
{
if (StackPanelCanvasControls.Visibility == Visibility.Visible) BtnDrawLine_Click(lastMouseDownSender, null);
}
private void KeyHide(object sender, ExecutedRoutedEventArgs e) {
private void KeyHide(object sender, ExecutedRoutedEventArgs e)
{
SymbolIconEmoji_MouseUp(null, null);
}
}
+4 -8
View File
@@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ink_Canvas {
public static class XamlGraphicsIconGeometries {
namespace Ink_Canvas
{
public static class XamlGraphicsIconGeometries
{
public static string LinedCursorIcon =
"F1 M24,24z M0,0z M5.72106,15.9716L3.71327,3.00395C3.6389,2.6693 3.65747,2.41831 3.76902,2.25099 3.88057,2.08366 4.0479,2 4.271,2 4.4941,2 4.71711,2.07437 4.94021,2.2231 6.72502,3.39438 9.28149,5.10481 12.6094,7.3544 15.677,9.45526 18.1125,11.1285 19.9159,12.3742 20.1204,12.5229 20.2505,12.6995 20.3062,12.904 20.362,13.1085 20.3249,13.2944 20.1947,13.4618 20.0832,13.6105 19.8973,13.6849 19.637,13.6849L13.3902,13.6849 17.6291,19.7365C17.722,19.8666 17.75,20.0153 17.7128,20.1827 17.6942,20.3314 17.6198,20.4522 17.4897,20.5452L15.5654,21.8838C15.4353,21.9768 15.2865,22.0139 15.1192,21.9953 14.9704,21.9582 14.8496,21.8745 14.7566,21.7444L10.2389,15.2745 7.58956,19.9038C7.45942,20.1269 7.30144,20.2756 7.11552,20.35 6.92961,20.4058 6.75292,20.3872 6.5856,20.2942 6.43686,20.2013 6.34392,20.0339 6.30673,19.7922L6.00007,17.8959C5.88852,17.0779,5.79543,16.4364,5.72106,15.9716z";
+16 -9
View File
@@ -4,30 +4,37 @@ using System.Linq;
using System.Threading;
using System.Windows;
namespace Ink_Canvas {
public partial class MainWindow : Window {
private int lastNotificationShowTime = 0;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
private int lastNotificationShowTime;
private int notificationShowTime = 2500;
public static void ShowNewMessage(string notice, bool isShowImmediately = true) {
public static void ShowNewMessage(string notice, bool isShowImmediately = true)
{
(Application.Current?.Windows.Cast<Window>().FirstOrDefault(window => window is MainWindow) as MainWindow)
?.ShowNotification(notice, isShowImmediately);
}
public void ShowNotification(string notice, bool isShowImmediately = true) {
try {
public void ShowNotification(string notice, bool isShowImmediately = true)
{
try
{
lastNotificationShowTime = Environment.TickCount;
TextBlockNotice.Text = notice;
AnimationsHelper.ShowWithSlideFromBottomAndFade(GridNotifications);
new Thread(new ThreadStart(() => {
new Thread(() =>
{
Thread.Sleep(notificationShowTime + 300);
if (Environment.TickCount - lastNotificationShowTime >= notificationShowTime)
Application.Current.Dispatcher.Invoke(() => {
Application.Current.Dispatcher.Invoke(() =>
{
AnimationsHelper.HideWithSlideAndFade(GridNotifications);
});
})).Start();
}).Start();
}
catch { }
}
File diff suppressed because it is too large Load Diff

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