WinForms Standard Development
执行原则
- 先读取最近的解决方案、项目文件(.csproj)、Program.cs、目标窗体及其 .Designer.cs,再直接实施。
- 沿用现有 .NET 版本(.NET Framework / .NET Core+)、命名空间、分层方式、数据访问方案和目录结构,不为统一偏好迁移架构。
- 完成用户要求的最小桌面端闭环,包括界面、控件、事件、业务服务和必要的持久化;不添加无关功能。
- 根据现有代码和常见约定补全低风险细节。仅在业务口径、数据覆盖、系统权限、外部发送或发布策略不明确且会实质改变结果时提问。
- 采用最小差异修改,保留用户已有改动,不格式化、改名或重构无关代码。
UI 构建与可视化设计器
- 窗体界面优先采用 Visual Studio 拖拽式设计器构建,控件生成、命名、位置与基础样式统一交由
Form.Designer.cs管理,方便后期修改。 - 禁止在业务代码中手写
new Label()、new Button()、new TextBox()、CreateLabel()、BuildXxxControl()等控件实例化代码;动态创建仅限确需运行时按数据量生成的场景,并集中封装。 - 不直接手工编辑
Form.Designer.cs中设计器生成的InitializeComponent()内容;需要调整布局、命名或样式时回到设计器操作。 - 为输入、加载、空状态、错误提示和重复提交提供需求所需的最小处理。
控件命名规范
- 在设计器拖入控件后立即改用「前缀 + 业务含义」命名,如
btnSubmit、lblStatus、txtUserName;禁止保留button1、label2、textBox3等默认名。 - 控件前缀遵循 WinForms 惯例(详见
references/naming-conventions.md),业务含义使用清晰的名词短语,保持事件绑定与代码逻辑可读。 - 为事件处理器自动使用
控件名_事件名命名(如btnSave_Click);重命名控件后同步设计器生成的字段与事件绑定。 - 完整前缀对照表与反例见
references/naming-conventions.md。
布局与自适应
- 优先使用控件的
Anchor(锚定)与Dock(停靠)属性进行相对布局,保证不同分辨率与窗口拉伸下的自适应。 - 避免用绝对坐标
Location与固定Size硬编码控件位置;确需像素级控制时给出理由并集中管理。 - 容器型布局(
TableLayoutPanel、FlowLayoutPanel、SplitContainer、Panel)用于复杂窗体的分区与自适应;简单窗体直接使用 Anchor/Dock。 - 使用布局控件时在初始化代码中明确行列比例、边距与停靠方式,保证缩放行为一致。
partial class 职责边界
- 严守 WinForms 局部类机制:
Form.Designer.cs仅存放设计器生成的 UI 初始化代码(字段声明 +InitializeComponent()),禁止手动修改。 - 所有业务逻辑、事件处理方法、自定义变量与字段统一写在
Form.cs中,不侵入 Designer 文件。 - 保持
InitializeComponent()是 Designer 文件唯一入口,业务代码不得在其中追加逻辑。 - 跨文件协作时明确每个 partial 文件的单一职责,避免业务状态散落到设计器文件。
事件驱动与逻辑解耦
- UI 层事件处理程序(如
btnSave_Click)保持极度精简:仅做参数校验、控件取值与调用业务方法,不做复杂数据库操作或耗时逻辑。 - 将业务逻辑抽离到独立的 Service 或 Manager 类(如
UserService、OrderManager),UI 只负责交互与展示。 - 事件处理器中先校验输入(必填、格式、范围),校验失败给出明确提示并提前返回。
- 业务方法返回结果或抛出结构化异常,由 UI 层统一转换为用户提示,不在事件处理器内堆叠 try/catch 与业务细节。
异步与 UI 线程
- 任何耗时操作(网络请求、大文件读写、复杂计算、数据库访问)必须使用
async/await或Task.Run处理,严禁在 UI 线程使用Thread.Sleep()或同步阻塞方法(.Wait()、.Result、Thread.Join()等)。 - 使用
await后天然回到 UI 线程更新控件;在后台任务中更新 UI 时使用Invoke/BeginInvoke或Control.Invoke封送回 UI 线程。 - 防止异步事件重复触发:进入时禁用按钮或加
_isBusy守卫,完成后恢复。 - 长时间任务优先使用
BackgroundWorker、IProgress<T>+Progress<T>或async void事件处理器(捕获全部异常)上报进度,避免界面假死。 - 详见
references/code-examples.md的异步与线程示例。
异常处理
- 在应用入口
Program.cs全局捕获未处理异常:注册Application.ThreadException与AppDomain.CurrentDomain.UnhandledException,记录日志并给出友好提示,防止程序无故崩溃。 - 业务层捕获异常后使用友好 UI 提示(
MessageBox或项目统一提示组件)代替直接抛出底层错误堆栈。 - 保留
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)确保 WinForms 异常路由到ThreadException。 - 捕获异常时记录完整堆栈用于排查,但面向用户只展示可理解的错误信息;不吞异常、不空 catch。
- 详见
references/code-examples.md的全局异常处理模板。
明确排除
- 不新增或修改单元测试、UI 自动化测试、测试数据、Mock、快照和覆盖率配置,除非用户明确要求。
- 不主动运行完整测试套件,不创建演示窗体、示例数据、设计文档、README 或占位项。
- 不为简单功能新增无需求的抽象层、框架、事件总线、缓存、埋点、插件系统或未来预留。
- 不使用硬编码路径、吞异常、跨线程强行更新控件或绕过权限来换取表面完成。
- 不擅自提交、推送、发布、打包、签名、安装或修改用户真实数据。
完成检查
- 确认所有控件由设计器管理且命名规范,
Form.Designer.cs未被手改,业务逻辑集中在Form.cs与 Service/Manager。 - 确认耗时操作已异步化、异常已全局捕获、事件处理器保持精简且输入有校验。
- 使用项目现有构建入口(MSBuild /
dotnet build)对受影响项目做一次轻量构建检查,不自动修复格式化与无关全仓检查。 - 只修复本次修改引入的问题;发现已有无关构建问题时停止扩大修改,并在交付中注明。
- 最终只报告实现摘要、关键文件、检查结果和必要的遗留问题。
Resources
references/naming-conventions.md— WinForms 控件前缀速查表、命名反例与正例。references/code-examples.md— partial class 边界、事件解耦、异步线程与全局异常处理的代码模板。