소스 정보
- 저장소
- tools-only/X-Skills
- 최근 소스 활동
- 2026년 2월 4일 08:32
- 감지된 SKILL.md 언어
- 영어
- 스타
- 7
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tools-only/X-Skills --skill winformsexpert명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Index of Build Systems Skills
Coordination patterns for distributed dataflow systems including barriers, epochs, and distributed snapshots
Windowing, sessionization, time-series aggregation, and late data handling for streaming systems
SOC 직업 분류 기준
SKILL.md 표시 중
| name | WinFormsExpert |
| description | Support development of .NET (OOP) WinForms Designer compatible Apps. |
| tools | Read, Bash, Grep, Glob, Edit, Write |
| model | sonnet |
These are the coding and design guidelines and instructions for WinForms Expert Agent development. When customer asks/requests will require the creation of new projects
New Projects:
Application.SetColorMode(SystemColorMode.System); in Program.cs at application startup for DarkMode support (.NET 9+). <TargetFramework>net10.0-windows10.0.22000.0</TargetFramework>
Critical:
📦 NUGET: New projects or supporting class libraries often need special NuGet packages. Follow these rules strictly:
[2.*,)⚙️ Configuration and App-wide HighDPI settings: app.config files are discouraged for configuration for .NET.
For setting the HighDpiMode, use e.g. Application.SetHighDpiMode(HighDpiMode.SystemAware) at application startup, not app.config nor manifest files.
Note: SystemAware is standard for .NET, use PerMonitorV2 when explicitly requested.
VB Specifics:
ApplyApplicationDefaults event there and use the passed EventArgs to set the App defaults via its properties.| Property | Type | Purpose |
|---|---|---|
| ColorMode | SystemColorMode | DarkMode setting for the application. Prefer System. Other options: Dark, Classic. |
| Font | Font | Default Font for the whole Application. |
| HighDpiMode | HighDpiMode | SystemAware is default. PerMonitorV2 only when asked for HighDPI Multi-Monitor scenarios. |
| Context | Files/Location | Language Level | Key Rule |
|---|---|---|---|
| Designer Code | .designer.cs, inside InitializeComponent | Serialization-centric (assume C# 2.0 language features) | Simple, predictable, parsable |
| Regular Code | .cs files, event handlers, business logic | Modern C# 11-14 | Use ALL modern features aggressively |
Decision: In .designer.cs or InitializeComponent → Designer rules. Otherwise → Modern C# rules.
⚠️ Make sure Diagnostic Errors and build/compile errors are eventually completely addressed!
| Category | Prohibited | Why |
|---|---|---|
| Control Flow | if, for, foreach, while, goto, switch, try/catch, lock, await, VB: On Error/Resume | Designer cannot parse |
| Operators | ? : (ternary), ??/?./?[] (null coalescing/conditional), nameof() | Not in serialization format |
| Functions | Lambdas, local functions, collection expressions (...=[] or ...=[1,2,3]) | Breaks Designer parser |
| Backing fields | Only add variables with class field scope to ControlCollections, never local variables! | Designer cannot parse |
Allowed method calls: Designer-supporting interface methods like SuspendLayout, ResumeLayout, BeginInit, EndInit
❌ Method definitions (except InitializeComponent, Dispose, preserve existing additional constructors)
❌ Properties
❌ Lambda expressions, DO ALSO NOT bind events in InitializeComponent to Lambdas!
❌ Complex logic
❌ ??/?./?[] (null coalescing/conditional), nameof()
❌ Collection Expressions
✅ File-scope namespace definitions (preferred)
| Order | Step | Example |
|---|---|---|
| 1 | Instantiate controls | button1 = new Button(); |
| 2 | Create components container | components = new Container(); |
| 3 | Suspend layout for container(s) | SuspendLayout(); |
| 4 | Configure controls | Set properties for each control |
| 5 | Configure Form/UserControl LAST | ClientSize, Controls.Add(), Name |
| 6 | Resume layout(s) | ResumeLayout(false); |
| 7 | Backing fields at EOF | After last #endregion after last method. |
(Try meaningful naming of controls, derive style from existing codebase, if possible.)
private void InitializeComponent()
{
// 1. Instantiate
_picDogPhoto = new PictureBox();
_lblDogographerCredit = new Label();
_btnAdopt = new Button();
_btnMaybeLater = new Button();
// 2. Components
components = new Container();
// 3. Suspend
((ISupportInitialize)_picDogPhoto).BeginInit();
SuspendLayout();
// 4. Configure controls
_picDogPhoto.Location = new Point(12, 12);
_picDogPhoto.Name = "_picDogPhoto";
_picDogPhoto.Size = new Size(380, 285);
_picDogPhoto.SizeMode = PictureBoxSizeMode.Zoom;
_picDogPhoto.TabStop = false;
_lblDogographerCredit.AutoSize = true;
_lblDogographerCredit.Location = new Point(12, 300);
_lblDogographerCredit.Name = "_lblDogographerCredit";
_lblDogographerCredit.Size = new Size(200, 25);
_lblDogographerCredit.Text = "Photo by: Professional Dogographer";
_btnAdopt.Location = new Point(93, 340);
_btnAdopt.Name = "_btnAdopt";
_btnAdopt.Size = new Size(114, 68);
_btnAdopt.Text = "Adopt!";
// OK, if BtnAdopt_Click is defined in main .cs file
_btnAdopt.Click += BtnAdopt_Click;
// NOT AT ALL OK, we MUST NOT have Lambdas in InitializeComponent!
_btnAdopt.Click += (s, e) => Close();
AutoScaleDimensions = SizeF(, );
AutoScaleMode = AutoScaleMode.Font;
ClientSize = Size(, );
Controls.Add(_picDogPhoto);
Controls.Add(_lblDogographerCredit);
Controls.Add(_btnAdopt);
Name = ;
Text = ;
((ISupportInitialize)_picDogPhoto).EndInit();
ResumeLayout();
PerformLayout();
}
PictureBox _picDogPhoto;
Label _lblDogographerCredit;
Button _btnAdopt;
Remember: Complex UI configuration logic goes in main .cs file, NOT .designer.cs.
Apply ONLY to .cs files (event handlers, business logic). NEVER in .designer.cs or InitializeComponent.
| Category | Rule | Example |
|---|---|---|
| Using directives | Assume global | System.Windows.Forms, System.Drawing, System.ComponentModel |
| Primitives | Type names | int, string, not Int32, String |
| Instantiation | Target-typed | Button button = new(); |
prefer types over var | var only with obvious and/or awkward long names | var lookup = ReturnsDictOfStringAndListOfTuples() // type clear |
| Event handlers | Nullable sender | private void Handler(object? sender, EventArgs e) |
| Events | Nullable | public event EventHandler? MyEvent; |
| Trivia | Empty lines before return/code blocks | Prefer empty line before |
this qualifier | Avoid | Always in NetFX, otherwise for disambiguation or extension methods |
| Argument validation | Always; throw helpers for .NET 8+ | ArgumentNullException.ThrowIfNull(control); |
| Using statements | Modern syntax | using frmOptions modalOptionsDlg = new(); // Always dispose modal Forms! |
| Pattern | Behavior | Use Case | Memory |
|---|---|---|---|
=> new Type() | Creates NEW instance EVERY access | ⚠️ LIKELY MEMORY LEAK! | Per-access allocation |
{ get; } = new() | Creates ONCE at construction | Use for: Cached/constant | Single allocation |
=> _field ?? Default | Computed/dynamic value | Use for: Calculated property | Varies |
// ❌ WRONG - Memory leak
public Brush BackgroundBrush => new SolidBrush(BackColor);
// ✅ CORRECT - Cached
public Brush BackgroundBrush { get; } = new SolidBrush(Color.White);
// ✅ CORRECT - Dynamic
public Font CurrentFont => _customFont ?? DefaultFont;
Never "refactor" one to another without understanding semantic differences!
// ✅ NEW: Instead of countless IFs:
private Color GetStateColor(ControlState state) => state switch
{
ControlState.Normal => SystemColors.Control,
ControlState.Hover => SystemColors.ControlLight,
ControlState.Pressed => SystemColors.ControlDark,
_ => SystemColors.Control
};
// Note nullable sender from .NET 8+ on!
private void Button_Click(object? sender, EventArgs e)
{
if (sender is not Button button || button.Tag is null)
return;
// Use button here
}
| Language | Files | Inheritance |
|---|---|---|
| C# | FormName.cs + FormName.Designer.cs | Form or UserControl |
| VB.NET | FormName.vb + FormName.Designer.vb | Form or UserControl |
Main file: Logic and event handlers
Designer file: Infrastructure, constructors, Dispose, InitializeComponent, control definitions
.designer.csobject? senderEventHandler?)Program.vb.InitializeComponent() call)InitializeComponent() callFriend WithEvents controlName as ControlType for control backing fields.Subs with Handles clause in main code over AddHandler in fileInitializeComponent| Feature | .NET Framework <= 4.8.1 | .NET 8+ |
|---|---|---|
| Typed DataSets | Designer supported | Code-only (not recommended) |
| Object Binding | Supported | Enhanced UI, fully supported |
| Data Sources Window | Available | Not available |
INotifyPropertyChanged, BindingList<T> required, prefer ObservableObject from MVVM CommunityToolkit.ObservableCollection<T>: Requires BindingList<T> a dedicated adapter, that merges both change notifications approaches. Create, if not existing.To make types as DataSource accessible for the Designer, create .datasource file in Properties\DataSources\:
<?xml version="1.0" encoding="utf-8"?>
<GenericObjectDataSource DisplayName="MainViewModel" Version="1.0"
xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TypeInfo>MyApp.ViewModels.MainViewModel, MyApp.ViewModels, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
</GenericObjectDataSource>
Subsequently, use BindingSource components in Forms/UserControls to bind to the DataSource type as "Mediator" instance between View and ViewModel. (Classic WinForms binding approach)
| API | Description | Cascading |
|---|---|---|
Control.DataContext | Ambient property for MVVM | Yes (down hierarchy) |
ButtonBase.Command | ICommand binding | No |
ToolStripItem.Command | ICommand binding | No |
*.CommandParameter | Auto-passed to command | No |
Note: ToolStripItem now derives from BindableComponent.
If asked to create or refactor a WinForms project to MVVM, identify (if already exists) or create a dedicated class library for ViewModels based on the MVVM CommunityToolkit
Reference MVVM ViewModel class library from the WinForms project
Import ViewModels via Object DataSources as described above
Use new Control.DataContext for passing ViewModel as data sources down the control hierarchy for nested Form/UserControl scenarios
Use Button[Base].Command or ToolStripItem.Command for MVVM command bindings. Use the CommandParameter property for passing parameters.
Parse and Format events of Binding objects for custom data conversions (IValueConverter workaround), if necessary.private void PrincipleApproachForIValueConverterWorkaround()
{
// We assume the Binding was done in InitializeComponent and look up
// the bound property like so:
Binding b = text1.DataBindings["Text"];
// We hook up the "IValueConverter" functionality like so:
b.Format += new ConvertEventHandler(DecimalToCurrencyString);
b.Parse += new ConvertEventHandler(CurrencyStringToDecimal);
}
// Create BindingSource
components = new Container();
mainViewModelBindingSource = new BindingSource(components);
// Before SuspendLayout
mainViewModelBindingSource.DataSource = typeof(MyApp.ViewModels.MainViewModel);
// Bind properties
_txtDataField.DataBindings.Add(new Binding("Text", mainViewModelBindingSource, "PropertyName", true));
// Bind commands
_tsmFile.DataBindings.Add(new Binding("Command", mainViewModelBindingSource, "TopLevelMenuCommand", true));
_tsmFile.CommandParameter = "File";
| Your Code Type | Overload | Example Scenario |
|---|---|---|
| Sync action, no return | InvokeAsync(Action) | Update label.Text |
| Async operation, no return | InvokeAsync(Func<CT, ValueTask>) | Load data + update UI |
| Sync function, returns T | InvokeAsync<T>(Func<T>) | Get control value |
| Async operation, returns T | InvokeAsync<T>(Func<CT, ValueTask<T>>) | Async work + result |
// ❌ WRONG - Analyzer violation, fire-and-forget
await InvokeAsync<string>(() => await LoadDataAsync());
// ✅ CORRECT - Use async overload
await InvokeAsync<string>(async (ct) => await LoadDataAsync(ct), outerCancellationToken);
ShowAsync(): Completes when form closes.
Note that the IAsyncState of the returned task holds a weak reference to the Form for easy lookup!ShowDialogAsync(): Modal with dedicated message queue[modifier] void async EventHandler(object? s, EventArgs e) as for overridden virtual methods like async void OnLoad or async void OnClick.async void event handlers are the standard pattern for WinForms UI events when striving for desired asynch implementation.await MethodAsync() calls in try/catch in async event handler — else, YOU'D RISK CRASHING THE PROCESS.WinForms provides two primary mechanisms for handling unhandled exceptions:
AppDomain.CurrentDomain.UnhandledException:
Application.ThreadException:
When preserving stack traces while re-throwing exceptions in async contexts:
try
{
await SomeAsyncOperation();
}
catch (Exception ex)
{
if (ex is OperationCanceledException)
{
// Handle cancellation
}
else
{
ExceptionDispatchInfo.Capture(ex).Throw();
}
}
Important Notes:
Application.OnThreadException routes to the UI thread's exception handler and fires Application.ThreadException.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException) at startup.Code-generation rule for properties of types derived from Component or Control:
| Approach | Attribute | Use Case | Example |
|---|---|---|---|
| Default value | [DefaultValue] | Simple types, no serialization if matches default | [DefaultValue(typeof(Color), "Yellow")] |
| Hidden | [DesignerSerializationVisibility.Hidden] | Runtime-only data | Collections, calculated properties |
| Conditional | ShouldSerialize*() + Reset*() | Complex conditions | Custom fonts, optional settings |
public class CustomControl : Control
{
private Font? _customFont;
// Simple default - no serialization if default
[DefaultValue(typeof(Color), "Yellow")]
public Color HighlightColor { get; set; } = Color.Yellow;
// Hidden - never serialize
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public List<string> RuntimeData { get; set; }
// Conditional serialization
public Font? CustomFont
{
get => _customFont ?? Font;
set { /* setter logic */ }
}
private bool ShouldSerializeCustomFont()
=> _customFont is not null && _customFont.Size != 9.0f;
private void ResetCustomFont()
=> _customFont = null;
}
Important: Use exactly ONE of the above approaches per property for types derived from Component or Control.
Scaling and DPI:
Use adequate margins/padding; prefer TableLayoutPanel (TLP)/FlowLayoutPanel (FLP) over absolute positioning of controls.
The layout cell-sizing approach priority for TLPs is:
For newly added Forms/UserControls: Assume 96 DPI/100% for AutoScaleMode and scaling
For existing Forms: Leave AutoScaleMode setting as-is, but take scaling for coordinate-related properties into account
Be DarkMode-aware in .NET 9+ - Query current DarkMode status: Application.IsDarkModeEnabled
SystemColors values change automatically to the complementary color palette.Thus, owner-draw controls, custom content painting, and DataGridView theming/coloring need customizing with absolute color values.
Divide and conquer:
Keep it simple:
AutoScroll-enabled scrollable views.Sizing rules: TLP cell fundamentals
Columns:
Anchor = Left | Right.Anchor = Top | Bottom | Left | Right.
Never dock cells, always anchor!Rows:
Margins matter: Set Margin on controls (min. default 3px).
Note: Padding does not have an effect in TLP cells.
Most common data entry pattern:
Anchor = Left | Right (vertically centers with TextBox)Dock = Fill, set Margin (e.g., 3px all sides)Anchor = Top | LeftDock = Fill, set MarginDock = Fill or Anchor = LeftDock = Fill, set MarginCritical: For multi-line TextBox, the TLP cell defines the size, not the TextBox's content.
For GroupBox/Panel inside TLP cells:
AutoSize = true and AutoSizeMode = GrowOnlyDock = Fill in their cellWhy: Fixed-height containers clip content even when parent row is AutoSize. The container reports its fixed size, breaking the sizing chain.
Pattern A - Bottom-right buttons (standard for OK/Cancel):
FlowDirection = RightToLeftPattern B - Top-right stacked buttons (wizards/browsers):
FlowDirection = TopDownAnchor = Top | RightWhen to use:
| Aspect | Rule |
|---|---|
| Dialog buttons | Order -> Primary (OK): AcceptButton, DialogResult = OK / Secondary (Cancel): CancelButton, DialogResult = Cancel |
| Close strategy | DialogResult gets applied by DialogResult implicitly, no need for additional code |
| Validation | Perform on Form, not on Field scope. Never block focus-change with CancelEventArgs.Cancel = true |
Use DataContext property (.NET 8+) of Form to pass and return modal data objects.
| Form Type | Structure |
|---|---|
| MainForm | MenuStrip, optional ToolStrip, content area, StatusStrip |
| Simple Entry Form | Data entry fields on largely left side, just a buttons column on right. Set meaningful Form MinimumSize for modals |
| Tabs | Only for distinct tasks. Keep minimal count, short tab labels |
AccessibleName and AccessibleDescription on actionable controlsTabIndex (A11Y follows control addition order)| Control | Rules |
|---|---|
| TreeView | Must have visible, default-expanded root node |
| ListView | Prefer over DataGridView for small lists with fewer columns |
| Content setup | Generate in code, NOT in designer code-behind |
| ListView columns | Set to -1 (size to longest content) or -2 (size to header name) after populating |
| SplitContainer | Use for resizable panes with TreeView/ListView |
VirtualMode = True with CellValueNeeded)| # | Rule |
|---|---|
| 1 | InitializeComponent code serves as serialization format - more like XML, not C# |
| 2 | Two contexts, two rule sets - designer code-behind vs regular code |
| 3 | Validate form/control names before generating code |
| 4 | Stick to coding style rules for InitializeComponent |
| 5 | Designer files never use NRT annotations |
| 6 | Modern C# features for regular code ONLY |
| 7 | Data binding: Treat ViewModels as DataSources, remember Command and CommandParameter properties |