winforms-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWinForms Expert
WinForms 专家
Purpose
目的
Implement WinForms changes that compile, behave correctly at runtime, and remain editable in the
Visual Studio Designer. Treat and as a serialization format,
not ordinary application code; keep behavior in the main partial class and verify designer
usability whenever the environment permits.
InitializeComponent*.Designer.*实现能够编译、运行时行为正确且仍可在 Visual Studio Designer 中编辑的 WinForms 更改。将 和 视为序列化格式,而非普通应用程序代码;将行为保留在主 partial class 中,并在环境允许时验证 Designer 的可用性。
InitializeComponent*.Designer.*Execution Contract
执行约定
Before editing, list the workspace root and locate any task-specific validator, test script, or
documented verification command. Read its scenario selector and required arguments before choosing
an implementation. After editing:
- Run that narrow validator first and fix every failure it attributes to the change.
- Run the focused project build after the validator passes.
- If the build or any later edit changes source, rerun the narrow validator.
- Report those commands separately from runtime UI and Designer round-trip checks.
A successful build never substitutes for an available layout, binding, serialization, or
designer-safety validator. Do not finish after merely reading a validator or after a build succeeds.
Use the repository's actual command and arguments; the sequence should look like:
powershell
pwsh -NoProfile -File <task-validator.ps1> <scenario-arguments>
dotnet build <project> --nologo编辑前,列出工作区根目录,并查找任何特定于任务的验证器、测试脚本或已记录的验证命令。在选择实现方案之前,读取其场景选择器及所需参数。编辑后:
- 首先运行范围最窄的验证器,并修复其归因于本次更改的每一个失败。
- 验证器通过后,运行聚焦的项目构建。
- 如果构建或后续编辑更改了源代码,则重新运行范围最窄的验证器。
- 将这些命令与运行时 UI 和 Designer 往返检查分开报告。
成功的构建绝不能替代可用的布局、绑定、序列化或 Designer 安全性验证器。不要在仅阅读验证器或构建成功后结束工作。
使用仓库实际采用的命令和参数;顺序应如下:
powershell
pwsh -NoProfile -File <task-validator.ps1> <scenario-arguments>
dotnet build <project> --nologoBoundaries
边界
Use this skill for:
- Creating or changing a WinForms project, ,
Form, or custom control.UserControl - Editing designer-generated layout, event wiring, resources, or component fields.
- Diagnosing a Form Designer load, serialization, scaling, binding, or toolbox problem.
- Implementing WinForms-specific async, MVVM, accessibility, DPI, or dark-mode behavior.
Do not use it to:
- Convert the application to another UI framework unless the user explicitly requests migration.
- Rewrite working generated code for style alone.
- Change the target framework, language version, SDK, package strategy, startup model, DPI mode, or application-wide theme unless required by the request.
- Claim that the Visual Studio Designer works when it was not actually opened and exercised.
将此 skill 用于:
- 创建或修改 WinForms 项目、、
Form或自定义控件。UserControl - 编辑 Designer 生成的布局、事件连接、资源或组件字段。
- 诊断 Form Designer 加载、序列化、缩放、绑定或工具箱问题。
- 实现 WinForms 特有的异步、MVVM、无障碍、DPI 或深色模式行为。
不将其用于:
- 除非用户明确要求迁移,否则将应用程序转换为其他 UI 框架。
- 仅为样式而重写正常工作的生成代码。
- 除非请求需要,否则更改目标框架、语言版本、SDK、包管理策略、启动模型、DPI 模式或应用级主题。
- 在未实际打开并操作 Designer 的情况下声称 Visual Studio Designer 可以正常工作。
Inputs
输入
| Input | Required | How to obtain it |
|---|---|---|
| Requested UI behavior or defect | Yes | Use the user's request and reproduce the symptom when possible. |
| Project language and target framework | Yes | Inspect the project file; do not assume modern .NET or C#. |
| Existing Form/UserControl partial files | Yes | Find the main file, designer file, and matching |
| Repository conventions | Yes | Inspect nearby WinForms types, build scripts, analyzers, and package management. |
| Designer availability | No | Determine whether a compatible Visual Studio WinForms Designer can be opened. |
| 输入 | 必需 | 获取方式 |
|---|---|---|
| 请求的 UI 行为或缺陷 | 是 | 使用用户的请求,并在可能时重现症状。 |
| 项目语言和目标框架 | 是 | 检查项目文件;不要假定使用现代 .NET 或 C#。 |
| 现有的 Form/UserControl partial 文件 | 是 | 查找主文件、Designer 文件及匹配的 |
| 仓库约定 | 是 | 检查附近的 WinForms 类型、构建脚本、分析器和包管理方式。 |
| Designer 可用性 | 否 | 确定是否可以打开兼容的 Visual Studio WinForms Designer。 |
Non-Negotiable Designer Contract
不可妥协的 Designer 约定
There are two code contexts:
| Context | Files | Rule |
|---|---|---|
| Designer serialization | | Use simple, deterministic statements the designer can parse and regenerate. |
| Application behavior | Main partial class, services, view models | Use language features supported by the project's TFM and language version. |
In and designer files:
InitializeComponent- Keep control/component construction, property assignments, collection additions, layout suspension/resumption, resource application, and named event-handler wiring.
- Use class-level control/component fields. Do not add a control to ,
Controls,Items, or another serialized collection through a local variable.Columns - Use named event handlers defined in the main partial file. Never use lambdas or anonymous delegates in generated event wiring.
- Do not add control flow (, loops,
if,switch/try,catch,lock,await), local functions, expression-bodied logic, collection expressions, null-conditional or null-coalescing expressions, or other runtime decision logic.goto - Do not add business logic, data loading, validation, service calls, or methods other than the
established generated members such as and
InitializeComponent.Dispose - Preserve the generator's existing namespace style, qualification style, ordering, resources, and nullable treatment. Do not modernize generated syntax.
- Preserve existing constructors that the designer relies on. A designer-instantiated
/
Formmust have a usable parameterless construction path unless the project uses an established custom designer pattern.UserControl - Keep /
BeginInit,EndInit/SuspendLayout, and container ownership balanced.ResumeLayout - For C#, keep generated fields at class scope in the designer partial. For VB, preserve
fields and prefer
Friend WithEventsclauses in the main file.Handles
A safe sequence is:
InitializeComponent- Instantiate controls and components.
- Instantiate the when owned components require it.
IContainer - Call required and
BeginInitmethods.SuspendLayout - Assign child control/component properties.
- Add children to serialized collections and wire named handlers.
- Configure the containing Form/UserControl after its children.
- Call matching ,
EndInit, andResumeLayoutwhere appropriate.PerformLayout - Declare serialized backing fields in the generator's established location.
Move anything more complex to the main partial class, usually after has run.
InitializeComponent存在两种代码上下文:
| 上下文 | 文件 | 规则 |
|---|---|---|
| Designer 序列化 | | 使用 Designer 能够解析并重新生成的简单、确定性语句。 |
| 应用程序行为 | 主 partial class、services、view models | 使用项目 TFM 和语言版本支持的语言功能。 |
在 和 Designer 文件中:
InitializeComponent- 保留控件/组件构造、属性赋值、集合添加、布局暂停/恢复、资源应用和命名事件处理程序连接。
- 使用类级控件/组件字段。不要通过局部变量将控件添加到 、
Controls、Items或其他序列化集合中。Columns - 使用在主 partial 文件中定义的命名事件处理程序。生成的事件连接绝不使用 lambda 或 anonymous delegate。
- 不添加控制流(、循环、
if、switch/try、catch、lock、await)、局部函数、表达式体逻辑、集合表达式、空条件运算符或空合并运算符,也不要添加其他运行时决策逻辑。goto - 不添加业务逻辑、数据加载、验证、service 调用或 、
InitializeComponent等既有生成成员之外的方法。Dispose - 保留生成器现有的命名空间风格、限定名风格、顺序、资源和 nullable 处理方式。不要将生成的语法现代化。
- 保留 Designer 所依赖的现有构造函数。由 Designer 实例化的 /
Form必须具有可用的无参构造路径,除非项目采用既有的自定义 Designer 模式。UserControl - 保持 /
BeginInit、EndInit/SuspendLayout以及容器所有权平衡。ResumeLayout - 对于 C#,在 Designer partial 中将生成字段保留在类作用域内。对于 VB,保留 字段,并优先在主文件中使用
Friend WithEvents子句。Handles
安全的 顺序如下:
InitializeComponent- 实例化控件和组件。
- 当拥有的组件需要 时,将其实例化。
IContainer - 调用所需的 和
BeginInit方法。SuspendLayout - 赋值子控件/组件属性。
- 将子项添加到序列化集合并连接命名处理程序。
- 在子项之后配置所属的 Form/UserControl。
- 在适当位置调用匹配的 、
EndInit和ResumeLayout。PerformLayout - 在生成器既有的位置声明序列化后备字段。
将任何更复杂的内容移到主 partial class 中,通常放在 运行之后。
InitializeComponentRules That Change the Answer
会改变答案的规则
Use the symptom to choose one WinForms-specific repair. Do not list several plausible patterns when
the existing project and failure identify one.
| Symptom or request | Do | Never | Verify |
|---|---|---|---|
| A Form/UserControl builds but the Designer cannot instantiate it | Preserve the runtime constructor, add a designer-usable parameterless path, and defer dependency use until runtime load with an explicit design/null guard | Construct production services, open files, or query data from the designer path | The runtime composition root still supplies the real dependency; the design path reaches |
| Controls/components disappear, duplicate, or fail after Designer save/reopen | Restore the generated field/collection shape and balance every | Patch the symptom in | Save, close, reopen, and inspect the regenerated diff |
A designer-created | Create the | Add ad hoc disposal while leaving designer ownership inconsistent | Closing the Form disposes the container-owned component and the component remains designer-managed |
| Adding/removing list items does not refresh a bound WinForms list control | Use | Treat | Mutate the list after binding and observe the control update |
| Nested content clips at DPI, font, or localization changes | Inspect | Assume | Exercise resize plus the relevant DPI/font/text expansion |
| UI work is posted but completion/errors are lost | Put the operation in a | Keep the whole operation inside | Await the task-returning method through success and failure; verify the UI entry point delegates to it |
| Text must be localizable | Use the existing | Leave fallback UI text hard-coded in | Build, switch culture when possible, and perform a Designer save/reopen |
| A VB app needs startup, single-instance, or unhandled-UI hooks | Extend | Invent | The configured |
| Review finds no actual designer defect | Leave tracked project/source files byte-for-byte unchanged and report why the suspicious construct is harmless | Clean up warnings, reformat generated code, or modernize unrelated syntax | Run the narrow available check and focused build; confirm the source diff is empty |
| The workspace contains a task-specific validator or test script | Run the narrow repository-provided check after editing and before the generic build; treat its failure as evidence that the change is incomplete | Skip the specialized check because the project compiles, or claim a Designer round trip from static validation | Report the exact validator and build commands separately, then state whether runtime UI and Designer round-trip checks were actually available |
根据症状选择一种 WinForms 特定修复。如果现有项目和故障已经确定一种方案,不要列出多种可能模式。
| 症状或请求 | 应该 | 绝不能 | 验证 |
|---|---|---|---|
| Form/UserControl 可以构建,但 Designer 无法实例化它 | 保留运行时构造函数,添加可供 Designer 使用的无参路径,并将依赖项的使用延迟到运行时加载,同时添加显式的设计期/null 防护 | 在 Designer 路径中构造生产服务、打开文件或查询数据 | 运行时 composition root 仍提供真实依赖项;设计路径无需调用该依赖项即可到达 |
| 控件/组件在 Designer 保存并重新打开后消失、重复或失效 | 恢复生成的字段/集合结构,并确保每一对 | 在 | 保存、关闭、重新打开并检查重新生成的差异 |
Designer 创建的 | 创建 | 添加临时性的释放处理,却让 Designer 所有权保持不一致 | 关闭 Form 会释放由容器拥有的组件,且该组件仍由 Designer 管理 |
| 添加或移除列表项后,绑定的 WinForms 列表控件未刷新 | 使用 | 将 | 绑定后修改列表并观察控件更新 |
| 嵌套内容在 DPI、字体或本地化变化时被裁剪 | 从叶节点到每个父节点检查 | 假定 | 测试调整大小以及相关的 DPI、字体或文本扩展 |
| UI 工作已提交,但完成或错误结果丢失 | 将操作放入调用方或测试可以等待的 | 将整个操作保留在 | 通过成功和失败路径等待返回 Task 的方法;验证 UI 入口会委托给该方法 |
| 文本必须支持本地化 | 使用现有 | 在 | 构建、尽可能切换 culture,并执行 Designer 保存/重新打开 |
| VB 应用需要启动、单实例或未处理 UI hook | 扩展 | 自创 | 已配置的 |
| 审查后未发现实际的 Designer 缺陷 | 将受跟踪的项目/源文件保持逐字节不变,并说明可疑结构为何无害 | 清理警告、重新格式化生成代码或现代化无关语法 | 运行范围最窄的可用检查和聚焦构建;确认源文件差异为空 |
| 工作区包含特定于任务的验证器或测试脚本 | 编辑后、通用构建前运行仓库提供的范围最窄检查;将其失败视为变更尚未完成的证据 | 因为项目可以编译而跳过专门检查,或根据静态验证声称完成了 Designer 往返检查 | 分别报告确切的验证器与构建命令,然后说明运行时 UI 和 Designer 往返检查是否实际可用 |
Workflow
工作流
1. Establish the project constraints
1. 确定项目约束
- Inspect the solution/project, target framework, language, nullable setting, package management, application startup, and existing build commands.
- Identify whether the app targets modern .NET or .NET Framework. Preserve its current family unless migration is requested.
- Read the complete partial-file set and for every affected Form/UserControl before editing. Check base classes and nearby controls for repository conventions.
.resx - If the defect is designer-specific, record the exact load/serialization error and determine whether the problem occurs before making broad changes.
- 检查 solution/project、目标框架、语言、nullable 设置、包管理方式、应用程序启动方式和现有构建命令。
- 确定应用面向现代 .NET 还是 .NET Framework。除非请求迁移,否则保留其当前类型。
- 编辑前,读取每个受影响 Form/UserControl 的完整 partial 文件集和 。检查基类及附近控件,以了解仓库约定。
.resx - 如果缺陷与 Designer 有关,记录确切的加载/序列化错误,并在进行广泛更改前确定问题发生的位置。
2. Plan the serialization boundary
2. 规划序列化边界
- Classify each change as serialized UI state or runtime behavior.
- Put only designer-representable state in .
InitializeComponent - Put conditional setup, dynamic content, data loading, conversions, validation, and service interaction in the main partial class or another runtime type.
- Prefer the smallest designer diff. Do not reorder or reformat the whole generated file.
- If editing generated code is avoidable, use the Designer or a runtime initialization method instead. If direct editing is necessary, follow the existing generated shape exactly.
- 将每项更改分类为序列化 UI 状态或运行时行为。
- 仅在 中放置 Designer 可表示的状态。
InitializeComponent - 将条件设置、动态内容、数据加载、转换、验证和 service 交互放入主 partial class 或其他运行时类型中。
- 优先采用最小的 Designer 差异。不要重新排序或重新格式化整个生成文件。
- 如果可以避免编辑生成代码,则使用 Designer 或运行时初始化方法。如果必须直接编辑,则严格遵循现有生成结构。
3. Implement the UI structure
3. 实现 UI 结构
For new or substantially revised layouts:
- Prefer ,
TableLayoutPanel,FlowLayoutPanel, and nested UserControls over brittle absolute positioning.SplitContainer - Divide complex screens into small layout regions. Avoid a single oversized grid.
- Prefer for caption/single-line rows and columns,
AutoSizefor expandable content, andPercentonly for genuinely fixed-size content.Absolute - Preserve the existing form's . For new forms, choose scaling deliberately based on the project conventions rather than copying coordinates from another DPI.
AutoScaleMode - Ensure an autosized child container participates in the full sizing chain; a fixed-height
or
Panelinside an autosized row can still clip its contents.GroupBox - Set meaningful minimum sizes where a resizable or localized dialog could otherwise become unusable.
- Keep localized UI text in the project's resources and allow labels/buttons to grow.
For dialogs:
- Set ,
AcceptButton, and appropriateCancelButtonvalues.DialogResult - Validate the form as a whole when submitting. Do not trap users in a field by canceling every focus change.
- Dispose modal forms according to the project's ownership pattern.
对于新增或大幅修改的布局:
- 优先使用 、
TableLayoutPanel、FlowLayoutPanel和嵌套 UserControls,而不是脆弱的绝对定位。SplitContainer - 将复杂界面划分为较小的布局区域。避免使用单个过大的 grid。
- 对标题/单行行和列优先使用 ,对可扩展内容使用
AutoSize,仅对真正固定尺寸的内容使用Percent。Absolute - 保留现有 Form 的 。对于新 Form,应根据项目约定有意识地选择缩放方式,而不是从其他 DPI 环境复制坐标。
AutoScaleMode - 确保自动调整大小的子容器参与完整的尺寸计算链。自动调整行内固定高度的 或
Panel仍可能裁剪其内容。GroupBox - 在可调整大小或支持本地化的对话框可能变得不可用时,设置合理的最小尺寸。
- 将本地化 UI 文本保留在项目资源中,并允许 label/button 扩展。
对于对话框:
- 设置 、
AcceptButton和适当的CancelButton值。DialogResult - 提交时整体验证 Form。不要在每次焦点变化时都取消验证,从而将用户困在某个字段中。
- 根据项目的所有权模式释放模态 Form。
4. Add behavior outside generated code
4. 在生成代码之外添加行为
- Follow the project's language and style conventions; modern syntax belongs only in regular code.
- Keep UI-thread affinity explicit. Marshal control access from background work.
- A normal WinForms event handler resumes on its captured UI synchronization context after
async voidunless that context was deliberately bypassed. Direct control access there is valid. Use and awaitawaitwhen code can continue off-context, or when the task/repository contract explicitly requires a marshaled operation; do not rely on an unawaited post.InvokeAsync - For modern .NET versions that support it, select the overload matching whether the delegate is synchronous/asynchronous and whether it returns a value. Await the returned operation; do not create fire-and-forget UI work.
Control.InvokeAsync - is acceptable for WinForms event handlers and overrides that must return
async void, but catch exceptions around awaited work, handle cancellation intentionally, and surface unexpected failures through the application's established error path.void - Do not use application-level exception hooks as a substitute for handling expected failures.
covers UI-thread exceptions;
Application.ThreadExceptionis primarily a last-chance logging path and does not make continued execution safe.AppDomain.UnhandledException - Preserve property allocation semantics. Do not change a cached property into
or vice versa without confirming lifetime and disposal behavior.
=> new ...
For application-wide startup:
- Preserve the current startup model. C# projects may configure application defaults in
; VB projects normally use the VB Application Framework and
Program.cs, not a newly inventedApplicationEvents.vb.Program.vb - Use the APIs available to the actual TFM. Apply color mode or DPI defaults only when requested or consistent with the app's existing policy.
- Prefer when maintaining the normal .NET WinForms DPI behavior. Use
SystemAwareonly when the application is designed and tested for per-monitor scaling.PerMonitorV2
- 遵循项目的语言和风格约定;现代语法只应用于常规代码。
- 明确保持 UI 线程亲和性。后台工作访问控件时必须进行封送。
- 常规 WinForms 事件处理程序在
async void后会恢复到捕获的 UI 同步上下文,除非该上下文被有意绕过。因此,可以直接访问控件。当代码可能继续在上下文之外执行,或 task/repository 契约明确要求封送操作时,使用并等待await;不要依赖未等待的 post。InvokeAsync - 对于支持相关功能的现代 .NET 版本,选择与 delegate 是同步/异步以及是否返回值相匹配的 重载。等待返回的操作;不要创建 fire-and-forget UI 工作。
Control.InvokeAsync - 对于必须返回 的 WinForms 事件处理程序和 override,可以使用
void,但应捕获 await 工作周围的异常、有意识地处理取消,并通过应用程序既有错误路径报告意外故障。async void - 不要使用应用级异常 hook 代替对预期失败的处理。覆盖 UI 线程异常;
Application.ThreadException主要用于最后机会的日志记录,并不能保证继续执行是安全的。AppDomain.UnhandledException - 保留属性分配语义。在未确认生命周期和释放行为之前,不要将缓存属性改为 ,也不要进行相反的更改。
=> new ...
对于应用级启动:
- 保留当前启动模型。C# 项目可以在 中配置应用程序默认值;VB 项目通常使用 VB Application Framework 和
Program.cs,而不是自创ApplicationEvents.vb。Program.vb - 使用实际 TFM 中可用的 API。仅在请求需要或与现有应用策略一致时应用颜色模式或 DPI 默认值。
- 维护常规 .NET WinForms DPI 行为时,优先使用 。仅当应用专门针对每显示器缩放进行设计和测试时,才使用
SystemAware。PerMonitorV2
5. Implement binding and serialization deliberately
5. 有意识地实现绑定和序列化
For classic binding:
- Use for mutable bound objects and
INotifyPropertyChangedor an established adapter for list change notifications.BindingList<T> - Use as the designer/runtime mediator when that matches the existing design.
BindingSource - Put conversion logic in and
Binding.Formathandlers rather than embedding executable logic in designer code.Binding.Parse - Treat one-way-to-source requests carefully: classic WinForms does not provide a direct WPF-style mode. Document and test any workaround instead of implying native support.
Binding
For modern WinForms MVVM APIs, first confirm the TFM contains the requested API:
- Use for ambient view-model context when available.
Control.DataContext - Use ,
ButtonBase.Command, andToolStripItem.Commandwhen available.CommandParameter - Keep view models in a UI-independent project when the solution already uses that separation or the requested change benefits from it; do not add a new architecture for a small fix.
- If design-time object data sources are required, preserve or add the project's established
and
.datasourcepattern and verify it in the Designer.BindingSource
For custom / properties, choose one intentional CodeDOM serialization policy:
ComponentControl| Policy | Mechanism | Use |
|---|---|---|
| Serialize only when non-default | | Stable values with a meaningful default |
| Never serialize | | Runtime-only, calculated, or unsupported state |
| Serialize content | | Owned nested objects/collections intentionally edited in the property grid |
Import (or fully qualify its attributes). Keep default metadata and runtime
initialization directly aligned: for , initialize the
property or its backing field directly with ; do not hide the actual default behind a
second constant or factory. Do not combine contradictory policies. Test property-grid editing and
save/reload behavior for custom serialization changes.
System.ComponentModel[DefaultValue(typeof(Color), "Yellow")]Color.Yellow对于经典绑定:
- 对可变绑定对象使用 ,并使用
INotifyPropertyChanged或既有的列表更改通知适配器。BindingList<T> - 当 与现有设计一致时,将其作为 Designer/运行时中介。
BindingSource - 将转换逻辑放入 和
Binding.Format处理程序,而不是嵌入 Designer 代码。Binding.Parse - 谨慎处理单向绑定到源对象的请求:经典 WinForms 不提供直接等同于 WPF 模式的功能。应记录并测试任何替代方案,不要暗示存在原生支持。
Binding
对于现代 WinForms MVVM API,首先确认 TFM 包含所请求的 API:
- 在可用时,使用 提供环境级 view-model 上下文。
Control.DataContext - 在可用时,使用 、
ButtonBase.Command和ToolStripItem.Command。CommandParameter - 如果 solution 已将 view model 放在独立于 UI 的项目中,或者所请求的更改因此受益,则保持这种分离;不要为小修复引入新架构。
- 如果需要设计时对象数据源,保留或添加项目既有的 和
.datasource模式,并在 Designer 中验证。BindingSource
对于自定义 / 属性,选择一种有意图且明确的 CodeDOM 序列化策略:
ComponentControl| 策略 | 机制 | 用途 |
|---|---|---|
| 仅在值不同于默认值时序列化 | | 具有有意义默认值的稳定属性 |
| 绝不序列化 | | 仅用于运行时、计算得出或不支持的状态 |
| 序列化内容 | | 有意在属性网格中编辑的被拥有嵌套对象/集合 |
导入 (或完全限定其属性)。让默认元数据与运行时初始化直接保持一致:对于 ,直接将属性或其后备字段初始化为 ;不要将实际默认值隐藏在第二个常量或 factory 之后。不要组合相互矛盾的策略。测试自定义序列化更改的属性网格编辑及保存/重新加载行为。
System.ComponentModel[DefaultValue(typeof(Color), "Yellow")]Color.Yellow6. Check usability and accessibility
6. 检查可用性和无障碍
- Set logical order and verify keyboard-only traversal.
TabIndex - Add unambiguous mnemonics where the product uses them.
- Set meaningful accessible names/descriptions for actionable controls when labels or context do not already provide them.
- Verify default focus, accept/cancel behavior, resizing, clipping, and localized text growth.
- Check at the DPI/theme combinations relevant to the change. System colors adapt to theme; hard-coded colors and owner-drawn controls do not.
- For owner drawing, , icons, and custom painting, verify contrast in every supported theme rather than assuming dark-mode adaptation.
DataGridView
- 设置合理的 顺序并验证纯键盘导航。
TabIndex - 在产品使用助记符时,添加明确无歧义的助记符。
- 当 label 或上下文未提供相应信息时,为可操作控件设置有意义的无障碍名称/描述。
- 验证默认焦点、接受/取消行为、调整大小、裁剪和本地化文本扩展。
- 检查与更改相关的 DPI/主题组合。系统颜色会适应主题;硬编码颜色和自绘控件不会。
- 对于自绘、、图标和自定义绘制,应在每个受支持的主题中验证对比度,而不是假定其能够适应深色模式。
DataGridView
7. Validate in increasing-cost order
7. 按成本递增顺序进行验证
- Re-read the designer diff and confirm every statement is serialization-safe and every referenced field/handler exists in the correct partial class.
- Discover and run the repository's narrowest task-specific validation script or test when one is present. A generic build does not replace a designer/layout/binding validator.
- Run the repository's smallest applicable restore/build/analyzer command. Use Visual Studio MSBuild when the project type or .NET Framework dependencies require it.
- Run any remaining relevant automated tests.
- Launch the affected UI when possible and exercise creation, load, resize, keyboard navigation, binding, async/error paths, and close/disposal behavior.
- When Visual Studio with a compatible WinForms Designer is available:
- Open every changed Form/UserControl in the Designer.
- Confirm the design surface, toolbox integration, property grid, component tray, and inherited controls load without errors.
- Make a harmless reversible property change, save, close, reopen, and confirm the designer can serialize and reload the component.
- Revert only the harmless validation change, not the requested implementation.
- Build again after the serialization round trip.
- 重新阅读 Designer 差异,确认每条语句均可安全序列化,且引用的字段/处理程序存在于正确的 partial class 中。
- 查找并运行仓库中范围最窄的任务专用验证脚本或测试(如果存在)。通用构建不能替代 Designer/布局/绑定验证器。
- 运行仓库中适用的最小 restore/build/analyzer 命令。当项目类型或 .NET Framework 依赖项要求时,使用 Visual Studio MSBuild。
- 运行其余相关自动化测试。
- 在可能时启动受影响的 UI,并操作创建、加载、调整大小、键盘导航、绑定、异步/错误路径以及关闭/释放行为。
- 当可以使用带有兼容 WinForms Designer 的 Visual Studio 时:
- 在 Designer 中打开每个已更改的 Form/UserControl。
- 确认设计界面、工具箱集成、属性网格、组件托盘和继承控件均可无错误加载。
- 进行一项无害且可逆的属性更改,保存、关闭、重新打开,并确认 Designer 能够序列化和重新加载组件。
- 仅撤销无害的验证更改,不要撤销请求的实现。
- 序列化往返检查后再次构建。
Observable Completion Criteria
可观察的完成标准
A change is complete only when the checks applicable to the environment are observable:
- The project builds with no new compiler or analyzer errors.
- Relevant tests pass.
- The affected UI runs and the requested behavior is exercised, when launching is possible.
- No affected contains unsupported runtime logic or unresolved fields, handlers, resources, or unbalanced layout/initialization calls.
InitializeComponent - Changed custom properties survive a property-grid save/reopen round trip when applicable.
- Every changed Form/UserControl opens and reloads in the compatible Visual Studio Designer when designer access is available.
If Visual Studio, the Designer, Windows desktop access, a required workload, or a target runtime is
unavailable, report that validation as not run, state why, and list the exact checks that did
run. A successful build is not evidence that the Designer opens. Do not report the work as fully
designer-verified unless the design surface and serialization round trip were actually tested.
If a command fails:
- Report the command and the first actionable error.
- Distinguish a failure caused by the change from a missing tool/workload, incompatible platform, locked file, restore/network failure, or pre-existing repository failure.
- Fix failures caused by the change and rerun the check.
- Never replace a failed check with a success-shaped fallback or claim completion based only on source inspection.
Finish with a concise validation record:
- exact command and result.
Build: - exercised behavior, or
Runtime UI:with the blocking reason.not run - Form/UserControl opened, edited, saved, closed, and reopened; or
Designer round trip:with the blocking reason.not run - project policy and generated/startup files intentionally left unchanged.
Preserved:
仅当环境中适用的检查均可观察时,更改才算完成:
- 项目构建时没有新的编译器或分析器错误。
- 相关测试通过。
- 在可以启动时,受影响的 UI 能够运行并已操作所请求的行为。
- 受影响的 中不包含不受支持的运行时逻辑、未解析的字段、处理程序或资源,也不存在不平衡的布局/初始化调用。
InitializeComponent - 更改的自定义属性在适用时能够通过属性网格保存/重新打开往返检查。
- 在可以访问 Designer 时,每个已更改的 Form/UserControl 都能够在兼容的 Visual Studio Designer 中打开并重新加载。
如果无法使用 Visual Studio、Designer、Windows 桌面访问权限、所需 workload 或目标运行时,应将该验证报告为 not run,说明原因,并列出实际运行的确切检查。成功的构建不能证明 Designer 可以打开。除非实际测试了设计界面和序列化往返检查,否则不要声称工作已完全通过 Designer 验证。
如果命令失败:
- 报告该命令及第一个可操作的错误。
- 区分由本次更改导致的失败与缺少工具/workload、平台不兼容、文件锁定、restore/网络失败或仓库原有失败。
- 修复由本次更改导致的失败,并重新运行检查。
- 绝不能用成功形式的替代检查取代失败的检查,也绝不能仅基于源代码审查声称工作已完成。
最后提供一份简洁的验证记录:
- 确切命令及结果。
Build: - 已操作的行为,或
Runtime UI:及阻塞原因。not run - Form/UserControl 已执行打开、编辑、保存、关闭和重新打开;或
Designer round trip:及阻塞原因。not run - 有意保持不变的项目策略和生成/启动文件。
Preserved:
Common Pitfalls
常见陷阱
| Pitfall | Corrective rule |
|---|---|
Treating | Keep it as simple designer serialization; move decisions and behavior to the main partial class. |
| Putting lambdas or local control variables in generated code | Use class-level fields and named handlers. |
| Editing only one partial file | Read and keep the main file, designer file, |
| Reformatting the entire designer file | Make a surgical diff that follows generated ordering and style. |
| Assuming a build proves designer health | Open, edit, save, close, and reopen the design surface. |
| Adding constructor dependencies to a designable type | Preserve a designer-usable parameterless path or an established custom designer solution. |
| Fixed-size nested containers clipping controls | Preserve an autosizing chain and test resize plus DPI scaling. |
| Using absolute colors for dark mode without testing | Prefer system colors or explicitly theme and contrast-test custom drawing. |
Treating | Use |
| Assuming WPF binding or converter features exist | Use WinForms |
| Fire-and-forget UI marshaling or uncaught async event errors | Await |
Inventing | Use the VB Application Framework and |
| Changing DPI/theme/TFM/package policy during a UI fix | Preserve project policy unless the requested behavior requires and validates the change. |
| 陷阱 | 纠正规则 |
|---|---|
将 | 将其保持为简单的 Designer 序列化;将决策和行为移至主 partial class。 |
| 在生成代码中使用 lambda 或局部控件变量 | 使用类级字段和命名处理程序。 |
| 只编辑一个 partial 文件 | 读取并保持主文件、Designer 文件、 |
| 重新格式化整个 Designer 文件 | 采用遵循生成顺序和风格的精确差异。 |
| 假定构建可以证明 Designer 健康 | 打开、编辑、保存、关闭并重新打开设计界面。 |
| 为可设计类型添加构造函数依赖项 | 保留可供 Designer 使用的无参路径或既有的自定义 Designer 方案。 |
| 固定大小的嵌套容器裁剪控件 | 保留自动调整大小链,并测试调整大小和 DPI 缩放。 |
| 使用绝对颜色实现深色模式但未测试 | 优先使用系统颜色,或显式设置主题并对自定义绘制进行对比度测试。 |
将 | 使用 |
| 假定 WPF 绑定或 converter 功能存在 | 使用 WinForms |
| Fire-and-forget UI 封送或未处理的异步事件错误 | 等待 |
为 VB 应用程序自创 | 使用 VB Application Framework 和 |
| 在修复 UI 时更改 DPI、主题、TFM 或包管理策略 | 除非请求的行为需要且已通过验证,否则保留项目策略。 |