Skip to content

ICC-CE_MainWindow_结构重构提案 #683

Description

@HAILValkyrie

检查清单 | Checklist

  • 您确认此功能不存在于最新版本 | You confirm that this feature does not exist in the latest version.
  • 您确认此功能有开发的必要 | You confirm that this feature is worth developing.
  • 您确认此功能无法通过开发插件/自动化实现 | You confirm that this feature cannot be implemented through a plugin or automation.
  • 您没有为软件提交 Pull Request 或开发插件的能力 | You are unable to submit a Pull Request or develop a plugin for this software.
  • 您了解开发者无法及时回复和及时开发 | You understand that developers may not respond or implement features promptly.
  • 我已经仔细阅读过选项里的内容,并且知道这个选项不用勾选。 | I have carefully read the options and know that this option does not need to be checked.

功能描述 | Description

> 声明:本 issue 由 AI 协助测绘与撰写,全部数据已由本人人工复核,PR 由本人提交并对内容负责。
> - [x] 您没有为软件提交 Pull Request 或开发插件的能力(我能提交 PR,此项按表单要求勾选,特此说明)

一句话功能描述

希望能把挤在 MainWindow 里的计时、截图、热键这些功能逐步拆成独立的小模块,让代码更好维护、bug 更容易排查,全程不改变大家用起来的任何感受。

总原则

  1. 纯结构重构,零行为变化。不改 UI、不改用户可感知的任何流程、不修 bug。过程中若发现疑似 bug,单独开 issue 记录,绝不顺手改——否则 diff 无法审查,回归无法归因。
  2. 小步快走:拆成可能约 12 个工作阶段,每阶段一个独立分支、一个独立 PR、可单独 revert,不与任何其他改动混在一起。
  3. 每阶段有明确门禁:构建零错误 + 受影响功能人工冒烟通过,才进入下一阶段;某阶段出问题,只回退该阶段。

需求动机 | Motivation

背景与动机

对 net10 主线做了一次较完整的代码测绘(以当前 1.8.0.9 为准,数字动工前会再复核):

  • MainWindow 是一个巨型 partial 类:本体约 3,700 行,Ink Canvas/MainWindow_cs/ 下还有 58 个 partial 文件,合计约 5.8 万行。计时、截图、热键、托盘、通知、设置读写、PPT 集成都寄生在主窗体上;
  • 全库有 323 处空 catch(分布在 86 个文件),异常被静默吞掉——issue 区不少"玄学无法复现"的反馈(如 选择并拖拽墨迹后有概率导致墨迹始终处于可拖动状态 #662、在白板中选择并尝试缩放墨迹时墨迹异常 #654)与这种状态散落直接相关:不是没法修,是根本没有可诊断的信息;
  • 139 个文件直接引用 Dispatcher,线程归属靠约定而非结构保证;
  • 116 个辅助类平铺在 Helpers 目录下,没有按业务域划分。

带来的实际代价:修一个计时器问题要在一个 5 万行的类里干的昏天黑地;新贡献者很难安全地改代码;很多 bug 不是不能修,是不敢修。这次重构想解决的就是"不敢改"的问题。

期望设计 | Expected Design

阶段计划 | Plan

风险三档:🟢 机械操作、行为不变;🟡 结构移动、行为不变;🔴 涉及语义敏感区域的等价改写。

阶段 内容 风险 PR 方式
1 重构规范文档 + 可复现的构建基线 🟢 随首个代码 PR 附带
2 文件名规范化(消灭文件名中的 &)与 MainWindow_cs 目录语义修正 🔴 blame 断裂 单独一个 PR,纯 git mv
3 csproj 语言版本对齐到 C# 12 🟢 可独立合入
4 Helpers 按域分组(Ink / Ppt / Update / Security / UiShell) 🟡 纯移动零改动 每域一个 PR
5 从 MainWindow 提取低耦合服务:设置存储、托盘、通知、计时、截图、热键 🟡 每服务一个 PR
6 工具模式从字符串比较改为强类型枚举(持久化格式原样不动) 🟡 独立 PR
7 323 处空 catch 分 5 批治理(记日志 / 重抛 / 注释说明为何吞) 🟢 每批一个 PR,建议从这批开始审
8 PPT 集成(MW_PPT.cs)逐步提取为独立服务 🔴 耦合最高 分段合入,先讨论
9 ROTPPTManager(约 3,000 行)、AutoUpdateHelper(约 2,900 行)按职责拆 partial 🟡 各一个 PR
10 已提取服务中的 Dispatcher 直引收敛到统一调度入口 🔴 线程语义敏感 需讨论
11 xUnit 测试项目 + 纯逻辑代码首批单元测试 🟢 一个 PR
12 全量 diff 审计、Release 构建、冒烟清单、合入 🟢 —

完成后预期:MainWindow 体量下降 40% 以上,新增代码集中在 Services/ 下、与 UI 解耦、可单测。

三个高风险项,单独交代

这三处是改动最大、最容易出问题的地方,先说清楚做法和红线;任何一项如果不被认可,直接砍掉不影响其余阶段。

① 计时器服务化(阶段 5 的一部分)
把计时核心从 MW_Timer.cs(约 1,800 行)提取为独立的 TimerService:剩余时间、tick 递减、暂停语义收为不依赖 UI 的纯逻辑,窗口显隐留在主窗体。
红线:定时器类型原样搬移,不做 DispatcherTimer 与线程池 Timer 之间的互换(那是线程来源变化,不是等价改写);Tick 里碰 UI 的点统一收拢到入口方法,替换前后逐一核对。
预期收益:现在"暂停后 Tick 泄漏""停止后回调重入"这类隐患只能靠自觉避免,服务化后"任何时刻至多一个活跃 Tick"由结构保证。
验证:构建通过 + 服务内 Dispatcher/MainWindow 引用为零 + 新旧实现跑同一组计时场景(开始 → 运行 → 暂停 → 继续 → 结束)剩余时间序列逐秒一致,验证记录随 PR 附上。

② 文件改名(阶段 2)
代价是 git blame 在这些文件上断裂。补偿措施:纯 git mv,一个 commit 都不夹带逻辑改动,git log --follow 可以追历史;整个改名独立成一个 PR,方便一次性决定接受或拒绝。

③ Dispatcher 收敛(阶段 10)
只把已提取服务里直接引用 Dispatcher 的 UI 更新点改走统一调度入口——只换调用路径,不动线程模型;每一处替换都可以独立 revert。

测试承诺

严格遵守 CONTRIBUTING.md 中对大规模重构的全部要求:

  1. 每个 PR 附 Release 构建通过证明;
  2. 对重构涉及的功能做完整测试(UI 改动按三步法:样式、行为、i18n);
  3. 对所有变更点做回归可能性检查;
  4. 测试中发现的问题逐 commit 核对、针对性修复,不盲目改、不带病合入;
  5. 每个 PR 附人工冒烟清单(画板、墨迹、橡皮、PPT 模式、计时器、截图、热键等实际受影响的面)。

边界与取舍

  • 主动不做:不碰 UI 视觉体系统一(那是 [Feature Request] UI界面风格统一 #644 的范围)、不碰设置页信息架构([Feature Request] 设置页面规范处理 #642)、不做任何行为修复——与这两条 issue 正交,留给他们各自的方案。
  • 已知代价:目录结构变化会给在途 PR 制造合并冲突窗口,建议挑发版后的空窗期开始,或按维护者指定的节奏推进。
  • 数字口径:上文行数基于 1.8.0.4–1.8.0.9 期间的测绘,动工前会对当时 net10 最新 commit 重新复核并在第一个 PR 中给出确切数字。

请维护者拍板

  1. 按上表的颗粒度逐阶段提 PR 是否合适?还是更希望压缩成少数几个大 PR?
  2. 阶段 2 的改名 PR,能否接受 blame 断裂的代价?
  3. 三个高风险项(计时器、PPT 拆分、Dispatcher 收敛)是否需要先做小范围试点再展开?
  4. 什么时间窗口开始比较合适(避开在途 PR 冲突)?

没有回复的话,我默认按"先提阶段 7 空 catch 治理的第一批 PR 试水"起步——它风险最低、收益最直接,也正好验证协作流程。

其他补充信息 | Additional Info

No response

上传有关文件 | Upload relevant files

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions