winforms-expert について
winforms-expert は、ビルドの正しさと Visual Studio Designer との互換性を保ちながら、Windows Forms の変更を実装・診断するスキルです。プロジェクト固有の検証を案内し、デザイナーのシリアライズコードと実行時処理を分けます。
主な機能
- 01デザイナー向けシリアライズ指針
- 02プロジェクトと検証手段の特定
- 03ビルド前の重点検証
- 04WinForms 固有の修正指針
活用シーン
- 01Form やコントロールの追加・変更
- 02Designer の読み込み・保存問題の診断
- 03レイアウト、バインディング、DPI の問題修正
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dotnet/ skills --skill winforms-expertインストール後、Claude Code で/winforms-expertを入力して読み込まれたか確認します。
詳細
WinForms エキスパート
目的
コンパイルでき、実行時に正しく動作し、Visual Studio デザイナーで引き続き編集できる WinForms の変更を実装します。InitializeComponent と *.Designer.* は通常のアプリケーションコードではなく、シリアル化形式として扱います。動作はメインの部分クラスに実装し、環境が許す場合はデザイナーでの編集可能性を必ず確認します。
実行契約
編集する前に、ワークスペースのルートを一覧表示し、タスク固有のバリデーター、テストスクリプト、または文書化された検証コマンドを探します。実装方法を選ぶ前に、そのシナリオセレクターと必須引数を確認してください。編集後は、次の手順を実行します。
- まず対象を絞ったバリデーターを実行し、変更に起因するすべての失敗を修正します。
- バリデーターが合格したら、対象プロジェクトのビルドを実行します。
- ビルドまたはそれ以降の編集でソースが変更された場合は、対象を絞ったバリデーターを再実行します。
- これらのコマンドは、実行時 UI とデザイナーの往復確認とは分けて報告します。
成功したビルドで、利用可能なレイアウト、バインディング、シリアル化、またはデザイナーの安全性を確認するバリデーターを代用することはできません。バリデーターを読んだだけ、またはビルドに成功しただけで作業を終えないでください。
リポジトリで実際に使用されているコマンドと引数を使います。手順は次のようになります。
pwsh -NoProfile -File <task-validator.ps1> <scenario-arguments>
dotnet build <project> --nologo
適用範囲
次の場合にこのスキルを使用します。
- WinForms プロジェクト、
Form、UserControl、またはカスタムコントロールを作成または変更する。 - デザイナーで生成されたレイアウト、イベント配線、リソース、またはコンポーネントフィールドを編集する。
- Form デザイナーの読み込み、シリアル化、スケーリング、バインディング、またはツールボックスの問題を診断する。
- WinForms 固有の非同期処理、MVVM、アクセシビリティ、DPI、またはダークモードの動作を実装する。
次の場合には使用しないでください。
- ユーザーが移行を明示的に依頼していないのに、アプリケーションを別の UI フレームワークに変換する。
- スタイルだけを理由に、動作している生成コードを書き換える。
- 依頼に必要な場合を除き、ターゲットフレームワーク、言語バージョン、SDK、パッケージ戦略、起動モデル、DPI モード、またはアプリケーション全体のテーマを変更する。
- 実際に開いて操作していないのに、Visual Studio デザイナーが動作すると主張する。
入力
| 入力 | 必須 | 確認方法 |
|---|---|---|
| 依頼された UI の動作または不具合 | はい | ユーザーの依頼を確認し、可能であれば症状を再現します。 |
| プロジェクトの言語とターゲットフレームワーク | はい | プロジェクトファイルを確認します。最新の .NET や C# だと決めつけないでください。 |
| 既存の Form/UserControl の部分クラスファイル | はい | メインファイル、デザイナーファイル、対応する .resx を探します。 |
| リポジトリの規約 | はい | 近くにある WinForms 型、ビルドスクリプト、アナライザー、パッケージ管理を確認します。 |
| デザイナーを利用できるか | いいえ | 対応する Visual Studio WinForms デザイナーを開けるかどうかを確認します。 |
譲れないデザイナーの契約
コードのコンテキストは2種類あります。
| コンテキスト | ファイル | ルール |
|---|---|---|
| デザイナーのシリアル化 | *.Designer.cs、*.Designer.vb、InitializeComponent | デザイナーが解析して再生成できる、シンプルで決定的なステートメントを使用します。 |
| アプリケーションの動作 | メインの部分クラス、サービス、ビューモデル | プロジェクトの TFM と言語バージョンでサポートされている言語機能を使用します。 |
InitializeComponent とデザイナーファイルでは、次のルールに従ってください。
- コントロール/コンポーネントの生成、プロパティの割り当て、コレクションへの追加、レイアウトの一時停止/再開、リソースの適用、名前付きイベントハンドラーの配線を維持します。
- クラスレベルのコントロール/コンポーネントフィールドを使用します。ローカル変数を介してコントロールを
Controls、Items、Columns、またはその他のシリアル化対象コレクションに追加しないでください。 - メインの部分ファイルで定義された名前付きイベントハンドラーを使用します。生成されたイベント配線では、ラムダや匿名デリゲートを使用しないでください。
- 制御フロー(
if、ループ、switch、try/catch、lock、await、goto)、ローカル関数、式形式のロジック、コレクション式、null 条件演算子や null 合体演算子、その他の実行時の判定ロジックを追加しないでください。 - ビジネスロジック、データ読み込み、検証、サービス呼び出し、または
InitializeComponentやDisposeなど、既定の生成メンバー以外のメソッドを追加しないでください。 - ジェネレーターで既に使われている名前空間のスタイル、修飾スタイル、順序、リソース、null 許容の扱いを維持します。生成された構文を最新化しないでください。
- デザイナーが依存する既存のコンストラクターを維持します。デザイナーでインスタンス化する
Form/UserControlには、プロジェクトで既定のカスタムデザイナーパターンを使用している場合を除き、使用可能なパラメーターなしの生成方法が必要です。 BeginInit/EndInit、SuspendLayout/ResumeLayout、コンテナーの所有関係の対応を保ちます。- C# では、生成されたフィールドをデザイナーの部分クラス内のクラススコープに配置します。VB では、
Friend WithEventsフィールドを維持し、メインファイルではHandles句を優先します。
安全な InitializeComponent の手順は次のとおりです。
- コントロールとコンポーネントをインスタンス化します。
- 所有するコンポーネントに必要な場合は、
IContainerをインスタンス化します。 - 必要な
BeginInitメソッドとSuspendLayoutメソッドを呼び出します。 - 子コントロール/コンポーネントのプロパティを割り当てます。
- 子要素をシリアル化対象コレクションに追加し、名前付きハンドラーを配線します。
- 子要素の設定後に、包含する Form/UserControl を設定します。
- 適切な場合は、対応する
EndInit、ResumeLayout、PerformLayoutを呼び出します。 - ジェネレーターで定められた場所に、シリアル化対象のバッキングフィールドを宣言します。
より複雑な処理はメインの部分クラスに移し、通常は InitializeComponent の実行後に行います。
回答を左右するルール
症状に基づいて、WinForms 固有の修正を1つ選んでください。既存のプロジェクトとエラーから答えが特定できる場合は、可能性のあるパターンを複数挙げないでください。
| 症状または要望 | 実施すること | 絶対にしないこと | 確認方法 |
|---|---|---|---|
| Form/UserControl はビルドできるが、Designer でインスタンス化できない | ランタイム用コンストラクターを維持し、Designer で使用できる引数なしの経路を追加し、明示的なデザイン時/null ガードを使って、ランタイムで読み込まれるまで依存関係の使用を遅らせます | Designer 用の経路から本番サービスを構築したり、ファイルを開いたり、データを照会したりします | ランタイムのコンポジションルートから実際の依存関係が引き続き提供されること、およびデザイン時の経路でそれを呼び出すことなく InitializeComponent に到達すること |
| Designer の保存/再オープン後にコントロール/コンポーネントが消える、重複する、または動作しなくなる | 生成されたフィールド/コレクションの形を復元し、すべての BeginInit/EndInit および SuspendLayout/ResumeLayout のペアが揃うようにします | OnLoad で症状を回避したり、シリアル化されたコントロールをローカル変数に移したりします | 保存して閉じ、再度開いて、再生成された差分を確認します |
Designer で作成した Timer、BindingSource、画像リストなどのコンポーネントが Form より長く存続する | components コンテナーを作成し、コンポーネントのコンストラクターに渡します | Designer による所有関係が一貫しないまま、場当たり的な破棄処理を追加します | Form を閉じるとコンテナーが所有するコンポーネントが破棄され、コンポーネントが引き続き Designer で管理されること |
| リスト項目を追加/削除しても、バインドされた WinForms リストコントロールが更新されない | BindingList<T>、または WinForms のリスト変更通知を発行するリポジトリのアダプターを使用します | ObservableCollection<T> を WinForms の DataSource にそのまま使えるものとして扱います | バインド後にリストを変更し、コントロールが更新されることを確認します |
| DPI、フォント、ローカライズの変更時に、入れ子になったコンテンツが切れる | 末端からすべての親まで、AutoSize、AutoSizeMode、Dock、MinimumSize、MaximumSize、行/列スタイルを調べ、意図した最小サイズは維持しつつ、実際の拡大制限を取り除きます。また、拡大する階層に合わせて配置された兄弟コントロールも調べ、レスポンシブなレイアウトを維持します | AutoSize = true だけで十分だと思い込んだり、固定の Size を一つだけ大きくしたり、親コンテナーを迂回したり、コンテンツの拡大時に重なり得る位置に兄弟コントロールを残したりします | サイズ変更と、該当する DPI/フォント/テキストの拡大を試します |
| UI 処理はポストされるが、完了やエラーが失われる | 呼び出し元やテストから await できる Task を返すメソッドに処理を置き、必要な async void イベントハンドラーは await RefreshAsync() のみを実行するようにします。キャプチャされた WinForms コンテキスト上でコントロールを更新するか、コンテキスト外で実行される可能性がある場合は InvokeAsync を await し、finally でコントロールの状態を復元します | 処理全体を async void の中に置いたり、通常の方法として _ =、BeginInvoke、何もしないキャンセル用 catch、アプリケーション全体の例外フックを使用したりします | 成功時と失敗時の両方で、Task を返すメソッドを await します。UI のエントリーポイントがそのメソッドに処理を委譲することを確認します |
| テキストをローカライズする必要がある | 既存の .resx と ComponentResourceManager.ApplyResources のシリアル化パターンを使用します | フォールバック用の UI テキストを InitializeComponent にハードコードしたままにします | ビルドし、可能であればカルチャを切り替え、Designer の保存/再オープンを行います |
| VB アプリに起動、シングルインスタンス、または未処理の UI イベント用フックが必要 | ApplicationEvents.vb を拡張します。曖昧な場合は Microsoft.VisualBasic.ApplicationServices のイベント引数型を修飾します。既存の MainForm を復元してアクティブにし、前面に表示します。e.Exception をログに記録し、e.ExitApplication = True を明示的に設定します | Program.vb を新たに作成したり、Sub Main を追加したり、生成された起動処理を置き換えたり、エラー後の続行を暗黙のままにしたりします | 設定済みの StartupObject と生成されたアプリケーションファイルが変更されていないこと、新しいエントリーポイントが存在しないこと、最終報告に終了するかどうかの判断が記載されていること |
| レビューで実際の Designer の不具合が見つからない | 追跡対象のプロジェクト/ソースファイルをバイト単位で変更せず、不審な構造に問題がない理由を報告します | 警告を整理したり、生成コードを再フォーマットしたり、無関係な構文を最新化したりします | 利用可能な範囲で対象を絞ったチェックとビルドを実行し、ソース差分が空であることを確認します |
| ワークスペースにタスク固有のバリデーターまたはテストスクリプトがある | 編集後、汎用ビルドの前に、リポジトリが提供する対象を絞ったチェックを実行します。その失敗は変更が未完了である証拠として扱います | プロジェクトがコンパイルできることを理由に専用チェックを省略したり、静的検証だけで Designer の往復確認を行ったと主張したりします | バリデーターとビルドのコマンドを分けて正確に報告し、ランタイム UI と Designer の往復確認が実際に可能だったかどうかを述べます |
ワークフロー
1. プロジェクトの制約を把握する
- ソリューション/プロジェクト、ターゲットフレームワーク、言語、nullable 設定、パッケージ管理、アプリケーションの起動方法、既存のビルドコマンドを確認します。
- アプリが最新の .NET または .NET Framework のどちらを対象としているかを特定します。移行が依頼されていない限り、現在の系統を維持します。
- 編集する前に、影響を受ける各 Form/UserControl のすべての部分ファイルと
.resxを読みます。基底クラスと近くにあるコントロールを確認し、リポジトリの慣例を把握します。 - 不具合がデザイナー固有の場合は、正確な読み込み/シリアル化エラーを記録し、大規模な変更を行う前に問題が発生するタイミングを特定します。
2. シリアル化の境界を計画する
- 変更を、シリアル化される UI 状態または実行時の動作に分類します。
- デザイナーで表現できる状態だけを
InitializeComponentに記述します。 - 条件付きの設定、動的なコンテンツ、データの読み込み、変換、検証、サービスとの連携は、メインの部分クラスまたは別の実行時型に記述します。
- デザイナーの差分は最小限にします。生成ファイル全体の順序変更や書式変更は避けます。
- 生成コードの編集を避けられる場合は、デザイナーまたは実行時の初期化メソッドを使用します。直接編集が必要な場合は、既存の生成コードの形式に正確に従います。
3. UI の構造を実装する
新規または大幅に改訂するレイアウトでは、次の点に従います。
- 脆弱な絶対配置よりも、
TableLayoutPanel、FlowLayoutPanel、SplitContainer、入れ子にした UserControl を優先します。 - 複雑な画面は小さなレイアウト領域に分割します。単一の巨大なグリッドは避けます。
- キャプションや単一行の行・列には
AutoSize、拡張可能なコンテンツにはPercent、真に固定サイズのコンテンツに限りAbsoluteを優先します。 - 既存フォームの
AutoScaleModeを維持します。新しいフォームでは、別の DPI の座標をコピーするのではなく、プロジェクトの慣例に基づいて拡大縮小の方法を慎重に選びます。 - 自動サイズ調整される子コンテナーがサイズ調整の連鎖全体に含まれるようにします。自動サイズ調整される行に固定高さの
PanelやGroupBoxを配置すると、その内容が切り取られる場合があります。 - サイズ変更可能なダイアログやローカライズされたダイアログが使いにくくなる可能性がある場合は、適切な最小サイズを設定します。
- ローカライズ対象の UI テキストはプロジェクトのリソースに保持し、ラベルやボタンが広がるようにします。
ダイアログでは、次の点に従います。
AcceptButton、CancelButton、適切なDialogResultの値を設定します。- 送信時にフォーム全体を検証します。フォーカスが変わるたびにキャンセルして、ユーザーをフィールドから移動できない状態にしないでください。
- プロジェクトの所有権パターンに従って、モーダルフォームを破棄します。
4. 生成コードの外側に動作を追加する
- プロジェクトの言語とスタイルの規約に従います。最新の構文は通常のコードでのみ使用します。
- UI スレッドとの親和性を明示します。バックグラウンド処理からコントロールにアクセスする場合は、UI スレッドにマーシャリングします。
- 通常の WinForms
async voidイベントハンドラーは、意図的にそのコンテキストを回避していない限り、awaitの後にキャプチャ済みの UI 同期コンテキストで再開します。その場合、コントロールに直接アクセスしても問題ありません。コードがコンテキスト外で続行する可能性がある場合、またはタスク/リポジトリの契約でマーシャリングされた操作が明示的に必要な場合は、InvokeAsyncを使用して await します。await しない投稿処理には依存しないでください。 - 対応している最新の .NET バージョンでは、デリゲートが同期か非同期か、および戻り値があるかどうかに合った
Control.InvokeAsyncのオーバーロードを選択します。返された操作を await し、実行完了を待たない UI 処理は作成しないでください。 async voidは、voidを返す必要がある WinForms イベントハンドラーやオーバーライドでは使用できます。ただし、await した処理の周囲で例外を捕捉し、キャンセルを意図的に処理し、予期しない失敗はアプリケーションで確立されているエラー処理経路に通知してください。- アプリケーションレベルの例外フックを、予期される失敗への対処の代わりに使わないでください。
Application.ThreadExceptionは UI スレッド上の例外を対象とし、AppDomain.UnhandledExceptionは主に最後の手段としてのログ記録経路であり、実行を安全に継続できるようにするものではありません。 - プロパティの割り当てに関するセマンティクスを維持します。寿命と破棄の動作を確認せずに、キャッシュされたプロパティを
=> new ...に変更したり、その逆に変更したりしないでください。
アプリケーション全体の起動設定については、次の点に従います。
- 現在の起動モデルを維持します。C# プロジェクトでは
Program.csでアプリケーションの既定値を設定できます。VB プロジェクトでは通常、VB Application Framework とApplicationEvents.vbを使用し、新たにProgram.vbを作成することはありません。 - 実際の TFM で使用できる API を使用します。色モードや DPI の既定値は、要求された場合、またはアプリの既存の方針に沿う場合にのみ適用してください。
- 通常の .NET WinForms DPI 動作を維持する場合は、
SystemAwareを優先してください。PerMonitorV2は、アプリケーションがモニターごとのスケーリングに対応するよう設計・テストされている場合にのみ使用してください。
5. バインドとシリアル化を意図的に実装する
従来のバインドでは、次のようにします。
- 変更可能なバインド対象オブジェクトには
INotifyPropertyChangedを使用し、リストの変更通知にはBindingList<T>または確立されたアダプターを使用します。 - 既存の設計に合う場合は、デザイナーと実行時の仲介役として
BindingSourceを使用します。 - 実行可能なロジックをデザイナーコードに埋め込むのではなく、変換ロジックは
Binding.FormatおよびBinding.Parseハンドラーに記述します。 - ソースへの一方向バインドの要求には慎重に対応します。従来の WinForms
Bindingには、WPF 形式のモードが直接用意されていません。ネイティブでサポートされているかのように示すのではなく、回避策を文書化してテストします。
最新の WinForms MVVM API では、まず対象の TFM に要求された API が含まれていることを確認します。
- 利用できる場合は、アンビエントなビューモデルのコンテキストに
Control.DataContextを使用します。 - 利用できる場合は、
ButtonBase.Command、ToolStripItem.Command、およびCommandParameterを使用します。 - ソリューションですでに分離されている場合、または要求された変更にメリットがある場合は、ビューモデルを UI に依存しないプロジェクトに配置します。小規模な修正のために新しいアーキテクチャを追加しないでください。
- デザイン時のオブジェクトデータソースが必要な場合は、プロジェクトで確立されている
.datasourceとBindingSourceのパターンを維持または追加し、デザイナーで検証します。
カスタムの Component/Control プロパティでは、意図した CodeDOM シリアル化ポリシーを1つ選択します。
| ポリシー | 仕組み | 用途 |
|---|---|---|
| 既定値以外の場合にのみシリアル化 | [DefaultValue(...)] または対応する ShouldSerializeX/ResetX | 意味のある既定値を持つ安定した値 |
| シリアル化しない | [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] | 実行時のみの状態、計算された状態、またはサポートされない状態 |
| コンテンツをシリアル化 | DesignerSerializationVisibility.Content と、デザイナー互換の変更可能なコンテンツ | プロパティグリッドで意図的に編集する、所有する入れ子のオブジェクト/コレクション |
System.ComponentModel をインポートするか、その属性を完全修飾します。既定値のメタデータと実行時の初期化は、直接一致させます。たとえば、[DefaultValue(typeof(Color), "Yellow")] の場合、プロパティまたはそのバッキングフィールドを Color.Yellow で直接初期化します。実際の既定値を別の定数やファクトリの背後に隠さないでください。矛盾するポリシーを組み合わせないでください。カスタムのシリアル化を変更した場合は、プロパティグリッドでの編集と保存/再読み込みの動作をテストします。
6. 使いやすさとアクセシビリティを確認する
- 論理的な
TabIndexの順序を設定し、キーボードのみでの移動を検証します。 - 製品でニーモニックを使用している場合は、曖昧さのないニーモニックを追加します。
- ラベルやコンテキストで補えない場合は、操作可能なコントロールに意味のあるアクセシブル名や説明を設定します。
- 既定のフォーカス、確定/キャンセルの動作、サイズ変更、クリッピング、ローカライズされたテキストの伸長を確認します。
- 変更に関連する DPI とテーマの組み合わせで確認します。システムカラーはテーマに適応しますが、ハードコードされた色やオーナー描画コントロールは適応しません。
- オーナー描画、
DataGridView、アイコン、カスタム描画については、ダークモードに自動適応すると想定せず、サポートするすべてのテーマでコントラストを確認します。
7. コストの低い順に検証する
- デザイナーの差分を読み直し、すべての記述がシリアライズ可能であり、参照されているすべてのフィールド/ハンドラーが正しい partial クラスに存在することを確認します。
- リポジトリに固有の、最も範囲が狭い検証スクリプトまたはテストがあれば、それを特定して実行します。一般的なビルドでは、デザイナー/レイアウト/バインディングの検証に代えることはできません。
- リポジトリで適用できる最小限の復元/ビルド/アナライザーコマンドを実行します。プロジェクトの種類または .NET Framework の依存関係上必要な場合は、Visual Studio の MSBuild を使用します。
- 残っている関連する自動テストを実行します。
- 可能であれば対象の UI を起動し、作成、読み込み、サイズ変更、キーボード操作、バインディング、非同期処理/エラー経路、終了/破棄の動作を確認します。
- 互換性のある WinForms デザイナーを備えた Visual Studio が利用できる場合:
- 変更したすべての Form/UserControl をデザイナーで開きます。
- デザイン画面、ツールボックスとの連携、プロパティグリッド、コンポーネントトレイ、継承されたコントロールがエラーなく読み込まれることを確認します。
- 無害で元に戻せるプロパティ変更を行い、保存して閉じ、再度開き、デザイナーがコンポーネントをシリアライズして再読み込みできることを確認します。
- 要求された実装ではなく、検証のために行った無害な変更のみを元に戻します。
- シリアライズの往復確認後、再度ビルドします。
観測可能な完了条件
環境に適用できるチェック結果が観測できる場合にのみ、変更は完了です。
- プロジェクトが、新たなコンパイラーエラーまたはアナライザーエラーなしでビルドされる。
- 関連するテストが成功する。
- 起動可能な場合、対象の UI が実行され、要求された動作が確認されている。
- 影響を受ける
InitializeComponentに、サポート対象外の実行時ロジックや未解決のフィールド、ハンドラー、リソース、または対応関係の取れていないレイアウト/初期化呼び出しが含まれていない。 - 該当する場合、変更したカスタムプロパティが、プロパティグリッドでの保存/再オープン後も保持される。
- デザイナーを使用できる場合、変更したすべての Form/UserControl が互換性のある Visual Studio デザイナーで開き、再読み込みできる。
Visual Studio、デザイナー、Windows デスクトップ環境、必要なワークロード、または対象ランタイムが利用できない場合は、その検証を 未実施 として報告し、理由を示したうえで、実際に実施したチェックを正確に列挙します。ビルドの成功は、デザイナーが開くことの証拠にはなりません。デザイン画面とシリアライズの往復確認を実際にテストしていない場合、デザイナーで完全に検証済みと報告してはいけません。
コマンドが失敗した場合:
- コマンドと、対処可能な最初のエラーを報告します。
- 変更が原因の失敗と、ツール/ワークロードの不足、プラットフォームの非互換性、ファイルのロック、復元/ネットワークの失敗、または既存のリポジトリの問題による失敗を区別します。
- 変更が原因の失敗を修正し、チェックを再実行します。
- 失敗したチェックを、成功したように見せる代替手段に置き換えたり、ソースの確認だけに基づいて完了を主張したりしてはいけません。
最後に、簡潔な検証記録を記載します。
Build:正確なコマンドと結果。Runtime UI:確認した動作、または阻害理由を添えた未実施。Designer round trip:Form/UserControl を開き、編集、保存、終了、再度開いたこと。そうでない場合は、阻害理由を添えた未実施。Preserved:意図的に変更しなかったプロジェクトのポリシーおよび生成/起動ファイル。
よくある落とし穴
| 落とし穴 | 是正ルール |
|---|---|
InitializeComponent を通常の最新の C# コードとして扱う | 単純なデザイナーシリアル化として維持し、判断や動作はメインの partial クラスに移します。 |
| 生成コードにラムダ式やローカルのコントロール変数を記述する | クラスレベルのフィールドと名前付きハンドラーを使用します。 |
| 片方の partial ファイルだけを編集する | メインファイル、デザイナーファイル、.resx、基底型、プロジェクトメタデータを読み込み、整合性を保ちます。 |
| デザイナーファイル全体を再フォーマットする | 生成時の順序とスタイルに沿って、必要最小限の差分にします。 |
| ビルドできればデザイナーも正常だと思い込む | デザインサーフェスを開き、編集、保存、終了した後、再度開きます。 |
| デザイン可能な型にコンストラクター依存関係を追加する | デザイナーで使用可能な引数なしの経路、または既存のカスタムデザイナーソリューションを維持します。 |
| 固定サイズの入れ子コンテナーによってコントロールが切り取られる | 自動サイズ調整の連鎖を維持し、サイズ変更と DPI スケーリングをテストします。 |
| テストせずにダークモードで絶対色を使用する | システムカラーを優先するか、カスタム描画にテーマを適用し、コントラストをテストします。 |
ObservableCollection<T> を WinForms のリストソースとしてそのまま使えると思い込む | BindingList<T>、またはコレクションとプロパティの変更通知を橋渡しするアダプターを使用します。 |
| WPF のバインド機能やコンバーター機能が使えると思い込む | WinForms の Binding、BindingSource、Format、Parse を使用し、TFM 固有の API を確認します。 |
| UI のマーシャリングを未完了のまま放置する、または非同期イベントのエラーを捕捉しない | InvokeAsync を await し、async void の UI エントリーポイントでエラーを捕捉して通知します。 |
VB アプリケーション用に Program.vb を独自に作成する | VB Application Framework と ApplicationEvents.vb の規約を使用します。 |
| UI の修正時に DPI、テーマ、TFM、パッケージの方針を変更する | 要求された動作にその変更が必要で、検証できる場合を除き、プロジェクトの方針を維持します。 |