[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-microsoft-creating-winforms-custom-controls":3,"mdc-vlanlx-key":32,"related-repo-microsoft-creating-winforms-custom-controls":2819,"related-org-microsoft-creating-winforms-custom-controls":2912},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":22,"repoUrl":23,"updatedAt":24,"license":25,"forks":26,"topics":27,"repo":28,"sourceUrl":30,"mdContent":31},"creating-winforms-custom-controls","create custom WinForms controls","Creates custom controls and UserControls for modern WinForms (.NET 6+). Use when deriving from Control, UserControl, Button, TextBox, or other base controls, implementing custom rendering with OnPaint overrides, creating composite controls with child control composition, adding custom properties with [Browsable], [Category], or [DefaultValue] attributes for Designer support, implementing INotifyPropertyChanged for control properties, handling Layout\u002FLayoutEngine for custom sizing, creating scrollable controls with AutoScrollMinSize, implementing dark mode theming, or building List\u002FGrid\u002FTree-like controls. Also triggers for \"custom UserControl\", \"derive from Control\", \"owner-drawn control\", \"Designer properties\", \"[Browsable] attribute\", \"custom WinForms control\", \"LayoutEngine\", \"AutoScroll control\", and \"themed control\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"microsoft","Microsoft","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fmicrosoft.png",[12,16,19],{"name":13,"slug":14,"type":15},".NET","net","tag",{"name":17,"slug":18,"type":15},"Windows","windows",{"name":20,"slug":21,"type":15},"WinUI","winui",7,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fupgrade-agent-plugins","2026-07-03T16:31:30.1325",null,1,[],{"repoUrl":23,"stars":22,"forks":26,"topics":29,"description":25},[],"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fupgrade-agent-plugins\u002Ftree\u002FHEAD\u002Fplugins\u002Fupgrade-agent\u002Fextenders\u002Fupgrade-dotnet\u002Fupgrade\u002Fskills\u002Flazy\u002Fdesktop\u002Fwinforms\u002Fcreating-winforms-custom-controls","---\r\nname: creating-winforms-custom-controls\r\ndescription: >\r\n  Creates custom controls and UserControls for modern WinForms (.NET 6+). Use when deriving\r\n  from Control, UserControl, Button, TextBox, or other base controls, implementing custom\r\n  rendering with OnPaint overrides, creating composite controls with child control composition,\r\n  adding custom properties with [Browsable], [Category], or [DefaultValue] attributes for\r\n  Designer support, implementing INotifyPropertyChanged for control properties, handling\r\n  Layout\u002FLayoutEngine for custom sizing, creating scrollable controls with AutoScrollMinSize,\r\n  implementing dark mode theming, or building List\u002FGrid\u002FTree-like controls. Also triggers for\r\n  \"custom UserControl\", \"derive from Control\", \"owner-drawn control\", \"Designer properties\",\r\n  \"[Browsable] attribute\", \"custom WinForms control\", \"LayoutEngine\", \"AutoScroll control\",\r\n  and \"themed control\".\r\nmetadata:\r\n  discovery: lazy\r\n  traits: (.NET|CSharp|VisualBasic|DotNetCore) & WindowsForms\r\n---\r\n\r\n# When to Use This Skill\r\n\r\nAuthoring custom controls and UserControls for modern WinForms (.NET 6+, C# 13\u002F14): base-class selection, clip-proof layout\u002Fsizing, owner-draw, dark-mode theming, Designer serialization, and List\u002FGrid controls.\r\nUse this skill when asked to create, derive, or modernize a WinForms control, UserControl, owner-drawn control, themed\u002Fdark-mode-aware control, scrollable Control-derived control, or a List\u002FGrid-like control, and when wiring up Designer serialization for new control properties.\r\n\r\nUse it for designing UserControl to offload complex UI from forms, or when a reusable control is needed across multiple forms\u002Fprojects. Also use it for modernizing legacy controls to be dark-mode aware and DPI-aware.\r\n\r\n## Related Skills\r\n\r\n- [WinForms Development](..\u002Fbuilding-winforms-applications\u002FSKILL.md)\r\n- [WinForms Designer Code](..\u002Fmanaging-winforms-designer-code\u002FSKILL.md)\r\n- [WinForms Data Binding](..\u002Fmanaging-winforms-data-binding\u002FSKILL.md)\r\n- [WinForms Rendering](..\u002Fmanaging-winforms-rendering\u002FSKILL.md)\r\n- [WinForms High-DPI Fluent Layout](..\u002Fmanaging-winforms-high-dpi-layout\u002FSKILL.md)\r\n\r\n**Tenets:** Assume the project's house style:\r\n\r\n- **No `using` statements** ─ globally-imported namespaces only.\r\n- **NRTs enabled** ─ `#nullable enable` \u002F `nullable` mode.\r\n- **Modern C#** ─ pattern matching, `is`\u002F`and`\u002F`or`, switch expressions, collection initializers (`[]`).\r\n- **XML doc comments** ─ for all public members.\r\n- **`var` discipline** ─ use `var` only when the right-hand side is a constructor call or cast that makes the type obvious (e.g., `var cp = new CreateParams()`). Use explicit types for `int`, `bool`, `string`, `float`, `double`, `Color`, `Size`, `Point`, and similar short type names.\r\n- **Expression-bodied members** ─ use them for single-expression getters, simple one-liner methods, and read-only properties. Use block bodies when the logic has side effects or exceeds ~100 characters.\r\n- **Blank line before `return`** ─ improves readability in multi-statement methods.\r\n- **Be brief** ─ the code carries the intent.\r\n\r\n## 1. Pick the right base class\r\n\r\nDecide *generic reusable control* vs *composite\u002FLOB control* first.\r\n\r\n- **Generic, no domain (a slider, badge, gauge, custom button):** derive from `Control`, or the closest specialized base (`ButtonBase`, `ScrollableControl`, `ListControl`, `Panel`, `Label`, —¦). `Control` gives you a blank canvas with full paint\u002Finput control. `TextBoxBase` is **not available** ─ it is `internal`; if you need text-box-like behavior, derive from `TextBox` or compose one.\r\n- **Composite \u002F LOB \u002F domain-specific:** derive from `UserControl` and assemble constituent controls (see §5).\r\n- **List- or grid-shaped data:** derive from `DataGridView`, not `Control` from scratch (see §6).\r\n\r\nPrefer the most specific base that already solves the hard parts ─ don't reimplement `ButtonBase`'s focus\u002Fclick mechanics on a raw `Control`.\r\n\r\n## 2. Layout & sizing ─ make it clip-proof\r\n\r\nA control that looks fine at 100% DPI with the default font but clips at 200% \u002F large fonts is broken. Treat sizing as first-class wherever content needs a *minimum real estate* to render fonts\u002Fglyphs\u002Fimages without clipping.\r\n\r\nImplement these as a coherent set:\r\n\r\n- **`GetPreferredSize(Size proposedSize)`** ─ return the size genuinely needed for current content, font, padding, and DPI. Measure text with `TextRenderer.MeasureText` (it matches `TextRenderer.DrawText`). Always add `Padding.Size`. This is the single source of truth for \"how big do I need to be.\"\r\n- **`AutoSize`** ─ expose and honor it. When `true`, the layout engine calls `GetPreferredSize`; your job is to return an honest number. Re-raise layout when size-affecting content changes (`PerformLayout()` \u002F `Invalidate()`).\r\n- **`SetBounds(...)`** ─ override when you must clamp or adjust the bounds you're given (e.g. enforce a minimum). Respect the `BoundsSpecified` flags so you don't clobber a dimension the caller didn't set.\r\n- **`Padding`** ─ honor it in painting *and* `GetPreferredSize`. Content draws inside the padded rectangle.\r\n\r\nRule of thumb: an honest `GetPreferredSize` plus honored `AutoSize`\u002F`Padding` survives DPI and font scaling automatically.\r\n\r\nA typical `GetPreferredSize` for a text-bearing `Control`-derived control:\r\n\r\n```csharp\r\npublic override Size GetPreferredSize(Size proposedSize)\r\n{\r\n    Size textSize = TextRenderer.MeasureText(Text, Font);\r\n    Size content = new(\r\n        textSize.Width + Padding.Horizontal,\r\n        textSize.Height + Padding.Vertical);\r\n\r\n    return new Size(\r\n        Math.Max(content.Width, MinimumSize.Width),\r\n        Math.Max(content.Height, MinimumSize.Height));\r\n}\r\n```\r\n\r\n`OnTextChanged` \u002F `OnFontChanged` overrides should call `PerformLayout()` (and `Invalidate()` if owner-drawn) so a new preferred size is picked up while `AutoSize` is on.\r\n\r\n## 3. Owner-draw → always double-buffer\r\n\r\nWhen you take over painting (`OnPaint`, owner-draw cells, custom rendering), enable double buffering to eliminate flicker:\r\n\r\n```csharp\r\nSetStyle(\r\n    ControlStyles.UserPaint\r\n        | ControlStyles.AllPaintingInWmPaint\r\n        | ControlStyles.OptimizedDoubleBuffer,\r\n    true);\r\n```\r\n\r\nDo all painting in `OnPaint` ─ don't scatter logic into `OnPaintBackground`. Call `Invalidate()` (not `Refresh()`) to request a repaint so it coalesces with other invalidations rather than forcing a synchronous redraw.\r\n\r\n## 4. Dark mode & theming\r\n\r\nModern WinForms supports dark mode. Two things bite custom controls:\r\n\r\n### 4.1 Win32 scrollbars on a `Control`-derived class are not themed automatically\r\n\r\nIf you add scrollbars by calling Win32 (`WS_HSCROLL` \u002F `WS_VSCROLL`, `ShowScrollBar`, etc.) on a `Control` subclass, those scrollbars render in the classic (light) theme even in dark mode. To get them themed, override **`CreateParams`** and opt in:\r\n\r\n```csharp\r\nprotected override CreateParams CreateParams\r\n{\r\n    get\r\n    {\r\n        SetStyle(ControlStyles.ApplyThemingImplicitly, true); \u002F\u002F opt-in; false = opt-out\r\n        CreateParams cp = base.CreateParams;\r\n        \u002F\u002F add WS_HSCROLL \u002F WS_VSCROLL here as needed\r\n        return cp;\r\n    }\r\n}\r\n```\r\n\r\nThis **cannot** be done in the constructor: the base constructor reads `CreateParams` *before* your constructor body runs. It must live in the `CreateParams` getter, with the `SetStyle` call placed *before* `base.CreateParams` is read.\r\n\r\n### 4.2 `SystemColors` flip in dark mode ─ names become counter-intuitive\r\n\r\nIn dark mode, `SystemColors` are remapped to roughly complementary values. The **name no longer matches the apparent brightness, and that is intentional**: `ControlLightLight` is very bright in classic mode and correspondingly dark in dark mode. The remap is *not* always a strict mathematical complement ─ some colors are nudged to keep contrast adequate.\r\n\r\nConsequences:\r\n\r\n- If you use `SystemColors`, accept that the name describes its *classic-mode* role, not its color.\r\n- For **guaranteed contrast in both modes**, don't use `SystemColors` for your control's palette. Define your own colors as explicit `#AARRGGBB` values with **separate defaults for classic and dark mode**.\r\n- Pick the active set at runtime via `Application.IsDarkModeEnabled`, which reflects the *current* mode:\r\n\r\n```csharp\r\nColor faceColor = Application.IsDarkModeEnabled\r\n    ? Color.FromArgb(unchecked((int)0xFF2D2D30))\r\n    : Color.FromArgb(unchecked((int)0xFFF0F0F0));\r\n```\r\n\r\n## 5. UserControls & composite custom controls\r\n\r\nFor a `UserControl` (or any control composed of constituent controls):\r\n\r\n- **No design-time `Font` definitions.** Don't set `Font` on the UserControl or its children at design time. Design-time fonts pollute the HighDPI `AutoScaleDimensions` code generation, so when the user later re-opens the control in the Designer the generated scaling code is wrong. Adjust font *size* only at **runtime**.\r\n- **Layout in a `TableLayoutPanel`** with `AutoSize` rows\u002Fcolumns. Let the table compute geometry.\r\n- **The control itself exposes `AutoSize`** and an honest **`GetPreferredSize`** big enough to render every child unclipped across all HighDPI and large-font scenarios (§2). The `TableLayoutPanel` with AutoSize cells does most of this for you, but verify the outer control reports it.\r\n- **Very large UserControls** with many containers\u002Fcontrols where a single clip-proof preferred size is impractical: host the content in a scrolling `Panel` (`AutoScroll = true`) rather than forcing an unreasonable minimum size.\r\n\r\n## 6. List- \u002F Grid-like controls\r\n\r\nWhen asked for anything list- or grid-shaped, **derive from `DataGridView`** rather than building from scratch.\r\n\r\nFor image-rich or graphically rich data records, the best outcome is usually to **render the entire data item in one cell** via a custom `DataGridViewCell` ─ symbol fonts, multiple colors, multiple font sizes, multi-line layout, all in a single cell. Skip column headers in that case.\r\n\r\nKeep column headers (and therefore per-field columns) only when the context genuinely needs a schema overview or per-column sort\u002Ffilter. Even then, prefer **custom cell rendering** to get the rich graphical UI; don't fall back to plain text just because headers exist.\r\n\r\nWhenever cells vary in height, **compute row height from the tallest cell in the data row** ─ measure each cell's required height and set the row to the max, or the content clips.\r\n\r\n## 7. Designer serialization for new properties\r\n\r\nEvery public property you add must tell the Designer how to serialize it. Pick **exactly one** of these three mechanisms (they conflict if combined):\r\n\r\n1. **`[DesignerSerializationVisibility(...)]`** ─ `Hidden` for runtime-only\u002Fderived properties the Designer must not write to `InitializeComponent`; `Content` for collections whose items serialize individually.\r\n2. **`[DefaultValue(...)]`** ─ the property serializes only when its value differs from this constant. Use for simple properties with a fixed, compile-time-constant default.\r\n3. **`ResetXxx()` + `ShouldSerializeXxx()` pair** ─ `ShouldSerializeXxx` returns whether the value should be written; `ResetXxx` restores the default. **Use this** for ambient properties, and whenever a default is *not constant* (depends on another property or the theme) ─ `[DefaultValue]` can't express that.\r\n\r\nThe method pair, for a property whose default depends on the current theme:\r\n\r\n```csharp\r\n\u002F\u002F\u002F \u003Csummary>Gets or sets the color of the control's face.\u003C\u002Fsummary>\r\npublic Color FaceColor { get; set; } = DefaultFaceColor;\r\n\r\nprivate static Color DefaultFaceColor\r\n    => Application.IsDarkModeEnabled\r\n        ? Color.FromArgb(unchecked((int)0xFF2D2D30))\r\n        : Color.FromArgb(unchecked((int)0xFFF0F0F0));\r\n\r\n\u002F\u002F The Designer discovers these by naming convention ─ keep them private.\r\nprivate bool ShouldSerializeFaceColor()\r\n    => FaceColor != DefaultFaceColor;\r\n\r\nprivate void ResetFaceColor()\r\n    => FaceColor = DefaultFaceColor;\r\n```\r\n\r\nNote the convention: the methods are `private`, named exactly `ShouldSerialize\u003CProperty>` \u002F `Reset\u003CProperty>`, and take no parameters. Don't combine them with `[DefaultValue]` on the same property ─ the two mechanisms conflict.\r\n\r\nDon't leave a property with none of these ─ the Designer will either over-serialize or fail to round-trip.\r\n\r\n### 7.1 Property-window attributes\r\n\r\nBeyond serialization, decorate every new public property so it behaves well in the Properties window and IntelliSense. These are four *distinct* concerns:\r\n\r\n- **`[Category(\"Appearance\")]`** ─ the Properties-window group. Reuse standard names (`Appearance`, `Behavior`, `Layout`, `Data`, —¦) so your properties merge with the built-in ones.\r\n- **`[Description(\"...\")]`** ─ help text in the Properties window's description pane. Write it for a control *consumer*.\r\n- **`[Browsable(false)]`** ─ hides the property from the Properties window. Use for runtime-only state. It almost always also needs `[DesignerSerializationVisibility(Hidden)]` ─ hiding from the grid does *not* stop serialization.\r\n- **`[EditorBrowsable(EditorBrowsableState.Never | Advanced)]`** ─ controls IntelliSense visibility, independent of the grid. `Never` hides from completion; `Advanced` shows only when \"Hide advanced members\" is off.\r\n\r\nTo fully suppress an inherited property that's meaningless on your control (e.g. shadowing `Text`), combine all three on the `new`\u002F`override` member:\r\n\r\n```csharp\r\n[Browsable(false)]\r\n[EditorBrowsable(EditorBrowsableState.Never)]\r\n[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r\npublic override string Text\r\n{\r\n    get => base.Text;\r\n    set => base.Text = value;\r\n}\r\n```\r\n\r\nA normal, visible property reads like this:\r\n\r\n```csharp\r\n[Category(\"Appearance\")]\r\n[Description(\"The color used to paint the control's face.\")]\r\npublic Color FaceColor { get; set; } = DefaultFaceColor;\r\n```\r\n\r\n## 8. Construction order ─ `ISupportInitialize`\r\n\r\nDuring `InitializeComponent`, the Designer sets your properties one at a time in an order *you don't control*. If two properties are interdependent ─ or a setter does expensive work (re-layout, allocation, a Win32 round-trip) ─ the control repeats that work against a half-configured state, and may even throw because property B isn't set yet when property A's setter runs.\r\n\r\nImplement **`ISupportInitialize`** to defer it. The Designer emits `BeginInit()` before the property block and `EndInit()` after; do nothing expensive in between:\r\n\r\n```csharp\r\npublic class GaugeControl : Control, ISupportInitialize\r\n{\r\n    private bool _initializing;\r\n\r\n    public void BeginInit()\r\n        => _initializing = true;\r\n\r\n    public void EndInit()\r\n    {\r\n        _initializing = false;\r\n        RecalculateLayout(); \u002F\u002F the deferred work, done once, fully configured\r\n        Invalidate();\r\n    }\r\n\r\n    public int Minimum\r\n    {\r\n        get;\r\n        set\r\n        {\r\n            field = value;\r\n\r\n            if (!_initializing)\r\n            {\r\n                RecalculateLayout();\r\n                Invalidate();\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nEvery interdependent setter checks `_initializing` and skips the expensive path while it's `true`. `EndInit` runs that path exactly once. At runtime (no Designer), code that sets properties directly without calling `BeginInit`\u002F`EndInit` still works ─ `_initializing` is just `false`, so each setter does its work immediately.\r\n\r\n## 9. Designer support code (.NET 6+)\r\n\r\nDesigner functionality in .NET 6+ requires the **WinForms Designer SDK** NuGet package.\r\n\r\n- Use the current preview: **`Microsoft.WinForms.Designer.SDK 1.13.0-preview.2.24575.3`**. The latest stable (`1.6.0`) is missing features you'll likely need ─ prefer the preview.\r\n- Without shipping a separate Designer NuGet package, you **can** put the following in the *same .NET assembly as the control*: custom `CodeDomSerializer`s, custom `TypeConverter`s, and custom `DesignerActionList` (smart-tag) actions.\r\n- **Out of scope for this skill:** Designers with a *custom design-time UI*. Those can't live in the control assembly ─ they need a dedicated multi-assembly NuGet package (client side on .NET Framework 4.7.2, server-side process on .NET, and a multi-targeted communication layer). If the user needs that, say so and stop.\r\n\r\n## Quick checklist\r\n\r\n- Most specific base class (`Control` generic, `UserControl` composite, `DataGridView` list\u002Fgrid).\r\n- `GetPreferredSize` honest; `AutoSize` + `Padding` honored; survives 200% DPI \u002F large fonts.\r\n- Owner-draw → `OptimizedDoubleBuffer | AllPaintingInWmPaint | UserPaint`; repaint via `Invalidate()`.\r\n- Dark mode: own `#AARRGGBB` palette per mode, switched on `Application.IsDarkModeEnabled`; Win32 scrollbars themed via `CreateParams` + `ApplyThemingImplicitly`.\r\n- UserControl: no design-time fonts, `TableLayoutPanel` with AutoSize cells, scrolling `Panel` if too large.\r\n- Every new property: `[DefaultValue]`, `[DesignerSerializationVisibility]`, or `ShouldSerializeXxx`\u002F`ResetXxx`; plus `[Category]`\u002F`[Description]`.\r\n- Interdependent or expensive property setters → `ISupportInitialize` with a `_initializing` guard.\r\n- Designer SDK preview `1.13.0-preview.2.24575.3` if design-time code is involved.\r\n",{"data":33,"body":37},{"name":4,"description":6,"metadata":34},{"discovery":35,"traits":36},"lazy","(.NET|CSharp|VisualBasic|DotNetCore) & WindowsForms",{"type":38,"children":39},"root",[40,49,55,60,67,118,129,353,359,379,515,534,540,552,557,691,716,735,846,885,891,904,951,986,992,997,1011,1056,1141,1194,1208,1242,1247,1322,1353,1359,1371,1500,1506,1523,1543,1555,1567,1573,1585,1701,1706,1825,1860,1865,1871,1883,2007,2035,2104,2109,2139,2151,2170,2201,2445,2502,2508,2520,2607,2613,2813],{"type":41,"tag":42,"props":43,"children":45},"element","h1",{"id":44},"when-to-use-this-skill",[46],{"type":47,"value":48},"text","When to Use This Skill",{"type":41,"tag":50,"props":51,"children":52},"p",{},[53],{"type":47,"value":54},"Authoring custom controls and UserControls for modern WinForms (.NET 6+, C# 13\u002F14): base-class selection, clip-proof layout\u002Fsizing, owner-draw, dark-mode theming, Designer serialization, and List\u002FGrid controls.\nUse this skill when asked to create, derive, or modernize a WinForms control, UserControl, owner-drawn control, themed\u002Fdark-mode-aware control, scrollable Control-derived control, or a List\u002FGrid-like control, and when wiring up Designer serialization for new control properties.",{"type":41,"tag":50,"props":56,"children":57},{},[58],{"type":47,"value":59},"Use it for designing UserControl to offload complex UI from forms, or when a reusable control is needed across multiple forms\u002Fprojects. Also use it for modernizing legacy controls to be dark-mode aware and DPI-aware.",{"type":41,"tag":61,"props":62,"children":64},"h2",{"id":63},"related-skills",[65],{"type":47,"value":66},"Related Skills",{"type":41,"tag":68,"props":69,"children":70},"ul",{},[71,82,91,100,109],{"type":41,"tag":72,"props":73,"children":74},"li",{},[75],{"type":41,"tag":76,"props":77,"children":79},"a",{"href":78},"..\u002Fbuilding-winforms-applications\u002FSKILL.md",[80],{"type":47,"value":81},"WinForms Development",{"type":41,"tag":72,"props":83,"children":84},{},[85],{"type":41,"tag":76,"props":86,"children":88},{"href":87},"..\u002Fmanaging-winforms-designer-code\u002FSKILL.md",[89],{"type":47,"value":90},"WinForms Designer Code",{"type":41,"tag":72,"props":92,"children":93},{},[94],{"type":41,"tag":76,"props":95,"children":97},{"href":96},"..\u002Fmanaging-winforms-data-binding\u002FSKILL.md",[98],{"type":47,"value":99},"WinForms Data Binding",{"type":41,"tag":72,"props":101,"children":102},{},[103],{"type":41,"tag":76,"props":104,"children":106},{"href":105},"..\u002Fmanaging-winforms-rendering\u002FSKILL.md",[107],{"type":47,"value":108},"WinForms Rendering",{"type":41,"tag":72,"props":110,"children":111},{},[112],{"type":41,"tag":76,"props":113,"children":115},{"href":114},"..\u002Fmanaging-winforms-high-dpi-layout\u002FSKILL.md",[116],{"type":47,"value":117},"WinForms High-DPI Fluent Layout",{"type":41,"tag":50,"props":119,"children":120},{},[121,127],{"type":41,"tag":122,"props":123,"children":124},"strong",{},[125],{"type":47,"value":126},"Tenets:",{"type":47,"value":128}," Assume the project's house style:",{"type":41,"tag":68,"props":130,"children":131},{},[132,151,177,218,228,317,327,343],{"type":41,"tag":72,"props":133,"children":134},{},[135,149],{"type":41,"tag":122,"props":136,"children":137},{},[138,140,147],{"type":47,"value":139},"No ",{"type":41,"tag":141,"props":142,"children":144},"code",{"className":143},[],[145],{"type":47,"value":146},"using",{"type":47,"value":148}," statements",{"type":47,"value":150}," ─ globally-imported namespaces only.",{"type":41,"tag":72,"props":152,"children":153},{},[154,159,161,167,169,175],{"type":41,"tag":122,"props":155,"children":156},{},[157],{"type":47,"value":158},"NRTs enabled",{"type":47,"value":160}," ─ ",{"type":41,"tag":141,"props":162,"children":164},{"className":163},[],[165],{"type":47,"value":166},"#nullable enable",{"type":47,"value":168}," \u002F ",{"type":41,"tag":141,"props":170,"children":172},{"className":171},[],[173],{"type":47,"value":174},"nullable",{"type":47,"value":176}," mode.",{"type":41,"tag":72,"props":178,"children":179},{},[180,185,187,193,195,201,202,208,210,216],{"type":41,"tag":122,"props":181,"children":182},{},[183],{"type":47,"value":184},"Modern C#",{"type":47,"value":186}," ─ pattern matching, ",{"type":41,"tag":141,"props":188,"children":190},{"className":189},[],[191],{"type":47,"value":192},"is",{"type":47,"value":194},"\u002F",{"type":41,"tag":141,"props":196,"children":198},{"className":197},[],[199],{"type":47,"value":200},"and",{"type":47,"value":194},{"type":41,"tag":141,"props":203,"children":205},{"className":204},[],[206],{"type":47,"value":207},"or",{"type":47,"value":209},", switch expressions, collection initializers (",{"type":41,"tag":141,"props":211,"children":213},{"className":212},[],[214],{"type":47,"value":215},"[]",{"type":47,"value":217},").",{"type":41,"tag":72,"props":219,"children":220},{},[221,226],{"type":41,"tag":122,"props":222,"children":223},{},[224],{"type":47,"value":225},"XML doc comments",{"type":47,"value":227}," ─ for all public members.",{"type":41,"tag":72,"props":229,"children":230},{},[231,242,244,249,251,257,259,265,267,273,274,280,281,287,288,294,295,301,302,308,309,315],{"type":41,"tag":122,"props":232,"children":233},{},[234,240],{"type":41,"tag":141,"props":235,"children":237},{"className":236},[],[238],{"type":47,"value":239},"var",{"type":47,"value":241}," discipline",{"type":47,"value":243}," ─ use ",{"type":41,"tag":141,"props":245,"children":247},{"className":246},[],[248],{"type":47,"value":239},{"type":47,"value":250}," only when the right-hand side is a constructor call or cast that makes the type obvious (e.g., ",{"type":41,"tag":141,"props":252,"children":254},{"className":253},[],[255],{"type":47,"value":256},"var cp = new CreateParams()",{"type":47,"value":258},"). Use explicit types for ",{"type":41,"tag":141,"props":260,"children":262},{"className":261},[],[263],{"type":47,"value":264},"int",{"type":47,"value":266},", ",{"type":41,"tag":141,"props":268,"children":270},{"className":269},[],[271],{"type":47,"value":272},"bool",{"type":47,"value":266},{"type":41,"tag":141,"props":275,"children":277},{"className":276},[],[278],{"type":47,"value":279},"string",{"type":47,"value":266},{"type":41,"tag":141,"props":282,"children":284},{"className":283},[],[285],{"type":47,"value":286},"float",{"type":47,"value":266},{"type":41,"tag":141,"props":289,"children":291},{"className":290},[],[292],{"type":47,"value":293},"double",{"type":47,"value":266},{"type":41,"tag":141,"props":296,"children":298},{"className":297},[],[299],{"type":47,"value":300},"Color",{"type":47,"value":266},{"type":41,"tag":141,"props":303,"children":305},{"className":304},[],[306],{"type":47,"value":307},"Size",{"type":47,"value":266},{"type":41,"tag":141,"props":310,"children":312},{"className":311},[],[313],{"type":47,"value":314},"Point",{"type":47,"value":316},", and similar short type names.",{"type":41,"tag":72,"props":318,"children":319},{},[320,325],{"type":41,"tag":122,"props":321,"children":322},{},[323],{"type":47,"value":324},"Expression-bodied members",{"type":47,"value":326}," ─ use them for single-expression getters, simple one-liner methods, and read-only properties. Use block bodies when the logic has side effects or exceeds ~100 characters.",{"type":41,"tag":72,"props":328,"children":329},{},[330,341],{"type":41,"tag":122,"props":331,"children":332},{},[333,335],{"type":47,"value":334},"Blank line before ",{"type":41,"tag":141,"props":336,"children":338},{"className":337},[],[339],{"type":47,"value":340},"return",{"type":47,"value":342}," ─ improves readability in multi-statement methods.",{"type":41,"tag":72,"props":344,"children":345},{},[346,351],{"type":41,"tag":122,"props":347,"children":348},{},[349],{"type":47,"value":350},"Be brief",{"type":47,"value":352}," ─ the code carries the intent.",{"type":41,"tag":61,"props":354,"children":356},{"id":355},"_1-pick-the-right-base-class",[357],{"type":47,"value":358},"1. Pick the right base class",{"type":41,"tag":50,"props":360,"children":361},{},[362,364,370,372,377],{"type":47,"value":363},"Decide ",{"type":41,"tag":365,"props":366,"children":367},"em",{},[368],{"type":47,"value":369},"generic reusable control",{"type":47,"value":371}," vs ",{"type":41,"tag":365,"props":373,"children":374},{},[375],{"type":47,"value":376},"composite\u002FLOB control",{"type":47,"value":378}," first.",{"type":41,"tag":68,"props":380,"children":381},{},[382,474,491],{"type":41,"tag":72,"props":383,"children":384},{},[385,390,392,398,400,406,407,413,414,420,421,427,428,434,436,441,443,449,451,456,458,464,466,472],{"type":41,"tag":122,"props":386,"children":387},{},[388],{"type":47,"value":389},"Generic, no domain (a slider, badge, gauge, custom button):",{"type":47,"value":391}," derive from ",{"type":41,"tag":141,"props":393,"children":395},{"className":394},[],[396],{"type":47,"value":397},"Control",{"type":47,"value":399},", or the closest specialized base (",{"type":41,"tag":141,"props":401,"children":403},{"className":402},[],[404],{"type":47,"value":405},"ButtonBase",{"type":47,"value":266},{"type":41,"tag":141,"props":408,"children":410},{"className":409},[],[411],{"type":47,"value":412},"ScrollableControl",{"type":47,"value":266},{"type":41,"tag":141,"props":415,"children":417},{"className":416},[],[418],{"type":47,"value":419},"ListControl",{"type":47,"value":266},{"type":41,"tag":141,"props":422,"children":424},{"className":423},[],[425],{"type":47,"value":426},"Panel",{"type":47,"value":266},{"type":41,"tag":141,"props":429,"children":431},{"className":430},[],[432],{"type":47,"value":433},"Label",{"type":47,"value":435},", —¦). ",{"type":41,"tag":141,"props":437,"children":439},{"className":438},[],[440],{"type":47,"value":397},{"type":47,"value":442}," gives you a blank canvas with full paint\u002Finput control. ",{"type":41,"tag":141,"props":444,"children":446},{"className":445},[],[447],{"type":47,"value":448},"TextBoxBase",{"type":47,"value":450}," is ",{"type":41,"tag":122,"props":452,"children":453},{},[454],{"type":47,"value":455},"not available",{"type":47,"value":457}," ─ it is ",{"type":41,"tag":141,"props":459,"children":461},{"className":460},[],[462],{"type":47,"value":463},"internal",{"type":47,"value":465},"; if you need text-box-like behavior, derive from ",{"type":41,"tag":141,"props":467,"children":469},{"className":468},[],[470],{"type":47,"value":471},"TextBox",{"type":47,"value":473}," or compose one.",{"type":41,"tag":72,"props":475,"children":476},{},[477,482,483,489],{"type":41,"tag":122,"props":478,"children":479},{},[480],{"type":47,"value":481},"Composite \u002F LOB \u002F domain-specific:",{"type":47,"value":391},{"type":41,"tag":141,"props":484,"children":486},{"className":485},[],[487],{"type":47,"value":488},"UserControl",{"type":47,"value":490}," and assemble constituent controls (see §5).",{"type":41,"tag":72,"props":492,"children":493},{},[494,499,500,506,508,513],{"type":41,"tag":122,"props":495,"children":496},{},[497],{"type":47,"value":498},"List- or grid-shaped data:",{"type":47,"value":391},{"type":41,"tag":141,"props":501,"children":503},{"className":502},[],[504],{"type":47,"value":505},"DataGridView",{"type":47,"value":507},", not ",{"type":41,"tag":141,"props":509,"children":511},{"className":510},[],[512],{"type":47,"value":397},{"type":47,"value":514}," from scratch (see §6).",{"type":41,"tag":50,"props":516,"children":517},{},[518,520,525,527,532],{"type":47,"value":519},"Prefer the most specific base that already solves the hard parts ─ don't reimplement ",{"type":41,"tag":141,"props":521,"children":523},{"className":522},[],[524],{"type":47,"value":405},{"type":47,"value":526},"'s focus\u002Fclick mechanics on a raw ",{"type":41,"tag":141,"props":528,"children":530},{"className":529},[],[531],{"type":47,"value":397},{"type":47,"value":533},".",{"type":41,"tag":61,"props":535,"children":537},{"id":536},"_2-layout-sizing-make-it-clip-proof",[538],{"type":47,"value":539},"2. Layout & sizing ─ make it clip-proof",{"type":41,"tag":50,"props":541,"children":542},{},[543,545,550],{"type":47,"value":544},"A control that looks fine at 100% DPI with the default font but clips at 200% \u002F large fonts is broken. Treat sizing as first-class wherever content needs a ",{"type":41,"tag":365,"props":546,"children":547},{},[548],{"type":47,"value":549},"minimum real estate",{"type":47,"value":551}," to render fonts\u002Fglyphs\u002Fimages without clipping.",{"type":41,"tag":50,"props":553,"children":554},{},[555],{"type":47,"value":556},"Implement these as a coherent set:",{"type":41,"tag":68,"props":558,"children":559},{},[560,598,642,664],{"type":41,"tag":72,"props":561,"children":562},{},[563,572,574,580,582,588,590,596],{"type":41,"tag":122,"props":564,"children":565},{},[566],{"type":41,"tag":141,"props":567,"children":569},{"className":568},[],[570],{"type":47,"value":571},"GetPreferredSize(Size proposedSize)",{"type":47,"value":573}," ─ return the size genuinely needed for current content, font, padding, and DPI. Measure text with ",{"type":41,"tag":141,"props":575,"children":577},{"className":576},[],[578],{"type":47,"value":579},"TextRenderer.MeasureText",{"type":47,"value":581}," (it matches ",{"type":41,"tag":141,"props":583,"children":585},{"className":584},[],[586],{"type":47,"value":587},"TextRenderer.DrawText",{"type":47,"value":589},"). Always add ",{"type":41,"tag":141,"props":591,"children":593},{"className":592},[],[594],{"type":47,"value":595},"Padding.Size",{"type":47,"value":597},". This is the single source of truth for \"how big do I need to be.\"",{"type":41,"tag":72,"props":599,"children":600},{},[601,610,612,618,620,626,628,634,635,641],{"type":41,"tag":122,"props":602,"children":603},{},[604],{"type":41,"tag":141,"props":605,"children":607},{"className":606},[],[608],{"type":47,"value":609},"AutoSize",{"type":47,"value":611}," ─ expose and honor it. When ",{"type":41,"tag":141,"props":613,"children":615},{"className":614},[],[616],{"type":47,"value":617},"true",{"type":47,"value":619},", the layout engine calls ",{"type":41,"tag":141,"props":621,"children":623},{"className":622},[],[624],{"type":47,"value":625},"GetPreferredSize",{"type":47,"value":627},"; your job is to return an honest number. Re-raise layout when size-affecting content changes (",{"type":41,"tag":141,"props":629,"children":631},{"className":630},[],[632],{"type":47,"value":633},"PerformLayout()",{"type":47,"value":168},{"type":41,"tag":141,"props":636,"children":638},{"className":637},[],[639],{"type":47,"value":640},"Invalidate()",{"type":47,"value":217},{"type":41,"tag":72,"props":643,"children":644},{},[645,654,656,662],{"type":41,"tag":122,"props":646,"children":647},{},[648],{"type":41,"tag":141,"props":649,"children":651},{"className":650},[],[652],{"type":47,"value":653},"SetBounds(...)",{"type":47,"value":655}," ─ override when you must clamp or adjust the bounds you're given (e.g. enforce a minimum). Respect the ",{"type":41,"tag":141,"props":657,"children":659},{"className":658},[],[660],{"type":47,"value":661},"BoundsSpecified",{"type":47,"value":663}," flags so you don't clobber a dimension the caller didn't set.",{"type":41,"tag":72,"props":665,"children":666},{},[667,676,678,682,684,689],{"type":41,"tag":122,"props":668,"children":669},{},[670],{"type":41,"tag":141,"props":671,"children":673},{"className":672},[],[674],{"type":47,"value":675},"Padding",{"type":47,"value":677}," ─ honor it in painting ",{"type":41,"tag":365,"props":679,"children":680},{},[681],{"type":47,"value":200},{"type":47,"value":683}," ",{"type":41,"tag":141,"props":685,"children":687},{"className":686},[],[688],{"type":47,"value":625},{"type":47,"value":690},". Content draws inside the padded rectangle.",{"type":41,"tag":50,"props":692,"children":693},{},[694,696,701,703,708,709,714],{"type":47,"value":695},"Rule of thumb: an honest ",{"type":41,"tag":141,"props":697,"children":699},{"className":698},[],[700],{"type":47,"value":625},{"type":47,"value":702}," plus honored ",{"type":41,"tag":141,"props":704,"children":706},{"className":705},[],[707],{"type":47,"value":609},{"type":47,"value":194},{"type":41,"tag":141,"props":710,"children":712},{"className":711},[],[713],{"type":47,"value":675},{"type":47,"value":715}," survives DPI and font scaling automatically.",{"type":41,"tag":50,"props":717,"children":718},{},[719,721,726,728,733],{"type":47,"value":720},"A typical ",{"type":41,"tag":141,"props":722,"children":724},{"className":723},[],[725],{"type":47,"value":625},{"type":47,"value":727}," for a text-bearing ",{"type":41,"tag":141,"props":729,"children":731},{"className":730},[],[732],{"type":47,"value":397},{"type":47,"value":734},"-derived control:",{"type":41,"tag":736,"props":737,"children":742},"pre",{"className":738,"code":739,"language":740,"meta":741,"style":741},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","public override Size GetPreferredSize(Size proposedSize)\n{\n    Size textSize = TextRenderer.MeasureText(Text, Font);\n    Size content = new(\n        textSize.Width + Padding.Horizontal,\n        textSize.Height + Padding.Vertical);\n\n    return new Size(\n        Math.Max(content.Width, MinimumSize.Width),\n        Math.Max(content.Height, MinimumSize.Height));\n}\n","csharp","",[743],{"type":41,"tag":141,"props":744,"children":745},{"__ignoreMap":741},[746,756,765,774,783,792,801,810,819,828,837],{"type":41,"tag":747,"props":748,"children":750},"span",{"class":749,"line":26},"line",[751],{"type":41,"tag":747,"props":752,"children":753},{},[754],{"type":47,"value":755},"public override Size GetPreferredSize(Size proposedSize)\n",{"type":41,"tag":747,"props":757,"children":759},{"class":749,"line":758},2,[760],{"type":41,"tag":747,"props":761,"children":762},{},[763],{"type":47,"value":764},"{\n",{"type":41,"tag":747,"props":766,"children":768},{"class":749,"line":767},3,[769],{"type":41,"tag":747,"props":770,"children":771},{},[772],{"type":47,"value":773},"    Size textSize = TextRenderer.MeasureText(Text, Font);\n",{"type":41,"tag":747,"props":775,"children":777},{"class":749,"line":776},4,[778],{"type":41,"tag":747,"props":779,"children":780},{},[781],{"type":47,"value":782},"    Size content = new(\n",{"type":41,"tag":747,"props":784,"children":786},{"class":749,"line":785},5,[787],{"type":41,"tag":747,"props":788,"children":789},{},[790],{"type":47,"value":791},"        textSize.Width + Padding.Horizontal,\n",{"type":41,"tag":747,"props":793,"children":795},{"class":749,"line":794},6,[796],{"type":41,"tag":747,"props":797,"children":798},{},[799],{"type":47,"value":800},"        textSize.Height + Padding.Vertical);\n",{"type":41,"tag":747,"props":802,"children":803},{"class":749,"line":22},[804],{"type":41,"tag":747,"props":805,"children":807},{"emptyLinePlaceholder":806},true,[808],{"type":47,"value":809},"\n",{"type":41,"tag":747,"props":811,"children":813},{"class":749,"line":812},8,[814],{"type":41,"tag":747,"props":815,"children":816},{},[817],{"type":47,"value":818},"    return new Size(\n",{"type":41,"tag":747,"props":820,"children":822},{"class":749,"line":821},9,[823],{"type":41,"tag":747,"props":824,"children":825},{},[826],{"type":47,"value":827},"        Math.Max(content.Width, MinimumSize.Width),\n",{"type":41,"tag":747,"props":829,"children":831},{"class":749,"line":830},10,[832],{"type":41,"tag":747,"props":833,"children":834},{},[835],{"type":47,"value":836},"        Math.Max(content.Height, MinimumSize.Height));\n",{"type":41,"tag":747,"props":838,"children":840},{"class":749,"line":839},11,[841],{"type":41,"tag":747,"props":842,"children":843},{},[844],{"type":47,"value":845},"}\n",{"type":41,"tag":50,"props":847,"children":848},{},[849,855,856,862,864,869,871,876,878,883],{"type":41,"tag":141,"props":850,"children":852},{"className":851},[],[853],{"type":47,"value":854},"OnTextChanged",{"type":47,"value":168},{"type":41,"tag":141,"props":857,"children":859},{"className":858},[],[860],{"type":47,"value":861},"OnFontChanged",{"type":47,"value":863}," overrides should call ",{"type":41,"tag":141,"props":865,"children":867},{"className":866},[],[868],{"type":47,"value":633},{"type":47,"value":870}," (and ",{"type":41,"tag":141,"props":872,"children":874},{"className":873},[],[875],{"type":47,"value":640},{"type":47,"value":877}," if owner-drawn) so a new preferred size is picked up while ",{"type":41,"tag":141,"props":879,"children":881},{"className":880},[],[882],{"type":47,"value":609},{"type":47,"value":884}," is on.",{"type":41,"tag":61,"props":886,"children":888},{"id":887},"_3-owner-draw-always-double-buffer",[889],{"type":47,"value":890},"3. Owner-draw → always double-buffer",{"type":41,"tag":50,"props":892,"children":893},{},[894,896,902],{"type":47,"value":895},"When you take over painting (",{"type":41,"tag":141,"props":897,"children":899},{"className":898},[],[900],{"type":47,"value":901},"OnPaint",{"type":47,"value":903},", owner-draw cells, custom rendering), enable double buffering to eliminate flicker:",{"type":41,"tag":736,"props":905,"children":907},{"className":738,"code":906,"language":740,"meta":741,"style":741},"SetStyle(\n    ControlStyles.UserPaint\n        | ControlStyles.AllPaintingInWmPaint\n        | ControlStyles.OptimizedDoubleBuffer,\n    true);\n",[908],{"type":41,"tag":141,"props":909,"children":910},{"__ignoreMap":741},[911,919,927,935,943],{"type":41,"tag":747,"props":912,"children":913},{"class":749,"line":26},[914],{"type":41,"tag":747,"props":915,"children":916},{},[917],{"type":47,"value":918},"SetStyle(\n",{"type":41,"tag":747,"props":920,"children":921},{"class":749,"line":758},[922],{"type":41,"tag":747,"props":923,"children":924},{},[925],{"type":47,"value":926},"    ControlStyles.UserPaint\n",{"type":41,"tag":747,"props":928,"children":929},{"class":749,"line":767},[930],{"type":41,"tag":747,"props":931,"children":932},{},[933],{"type":47,"value":934},"        | ControlStyles.AllPaintingInWmPaint\n",{"type":41,"tag":747,"props":936,"children":937},{"class":749,"line":776},[938],{"type":41,"tag":747,"props":939,"children":940},{},[941],{"type":47,"value":942},"        | ControlStyles.OptimizedDoubleBuffer,\n",{"type":41,"tag":747,"props":944,"children":945},{"class":749,"line":785},[946],{"type":41,"tag":747,"props":947,"children":948},{},[949],{"type":47,"value":950},"    true);\n",{"type":41,"tag":50,"props":952,"children":953},{},[954,956,961,963,969,971,976,978,984],{"type":47,"value":955},"Do all painting in ",{"type":41,"tag":141,"props":957,"children":959},{"className":958},[],[960],{"type":47,"value":901},{"type":47,"value":962}," ─ don't scatter logic into ",{"type":41,"tag":141,"props":964,"children":966},{"className":965},[],[967],{"type":47,"value":968},"OnPaintBackground",{"type":47,"value":970},". Call ",{"type":41,"tag":141,"props":972,"children":974},{"className":973},[],[975],{"type":47,"value":640},{"type":47,"value":977}," (not ",{"type":41,"tag":141,"props":979,"children":981},{"className":980},[],[982],{"type":47,"value":983},"Refresh()",{"type":47,"value":985},") to request a repaint so it coalesces with other invalidations rather than forcing a synchronous redraw.",{"type":41,"tag":61,"props":987,"children":989},{"id":988},"_4-dark-mode-theming",[990],{"type":47,"value":991},"4. Dark mode & theming",{"type":41,"tag":50,"props":993,"children":994},{},[995],{"type":47,"value":996},"Modern WinForms supports dark mode. Two things bite custom controls:",{"type":41,"tag":998,"props":999,"children":1001},"h3",{"id":1000},"_41-win32-scrollbars-on-a-control-derived-class-are-not-themed-automatically",[1002,1004,1009],{"type":47,"value":1003},"4.1 Win32 scrollbars on a ",{"type":41,"tag":141,"props":1005,"children":1007},{"className":1006},[],[1008],{"type":47,"value":397},{"type":47,"value":1010},"-derived class are not themed automatically",{"type":41,"tag":50,"props":1012,"children":1013},{},[1014,1016,1022,1023,1029,1030,1036,1038,1043,1045,1054],{"type":47,"value":1015},"If you add scrollbars by calling Win32 (",{"type":41,"tag":141,"props":1017,"children":1019},{"className":1018},[],[1020],{"type":47,"value":1021},"WS_HSCROLL",{"type":47,"value":168},{"type":41,"tag":141,"props":1024,"children":1026},{"className":1025},[],[1027],{"type":47,"value":1028},"WS_VSCROLL",{"type":47,"value":266},{"type":41,"tag":141,"props":1031,"children":1033},{"className":1032},[],[1034],{"type":47,"value":1035},"ShowScrollBar",{"type":47,"value":1037},", etc.) on a ",{"type":41,"tag":141,"props":1039,"children":1041},{"className":1040},[],[1042],{"type":47,"value":397},{"type":47,"value":1044}," subclass, those scrollbars render in the classic (light) theme even in dark mode. To get them themed, override ",{"type":41,"tag":122,"props":1046,"children":1047},{},[1048],{"type":41,"tag":141,"props":1049,"children":1051},{"className":1050},[],[1052],{"type":47,"value":1053},"CreateParams",{"type":47,"value":1055}," and opt in:",{"type":41,"tag":736,"props":1057,"children":1059},{"className":738,"code":1058,"language":740,"meta":741,"style":741},"protected override CreateParams CreateParams\n{\n    get\n    {\n        SetStyle(ControlStyles.ApplyThemingImplicitly, true); \u002F\u002F opt-in; false = opt-out\n        CreateParams cp = base.CreateParams;\n        \u002F\u002F add WS_HSCROLL \u002F WS_VSCROLL here as needed\n        return cp;\n    }\n}\n",[1060],{"type":41,"tag":141,"props":1061,"children":1062},{"__ignoreMap":741},[1063,1071,1078,1086,1094,1102,1110,1118,1126,1134],{"type":41,"tag":747,"props":1064,"children":1065},{"class":749,"line":26},[1066],{"type":41,"tag":747,"props":1067,"children":1068},{},[1069],{"type":47,"value":1070},"protected override CreateParams CreateParams\n",{"type":41,"tag":747,"props":1072,"children":1073},{"class":749,"line":758},[1074],{"type":41,"tag":747,"props":1075,"children":1076},{},[1077],{"type":47,"value":764},{"type":41,"tag":747,"props":1079,"children":1080},{"class":749,"line":767},[1081],{"type":41,"tag":747,"props":1082,"children":1083},{},[1084],{"type":47,"value":1085},"    get\n",{"type":41,"tag":747,"props":1087,"children":1088},{"class":749,"line":776},[1089],{"type":41,"tag":747,"props":1090,"children":1091},{},[1092],{"type":47,"value":1093},"    {\n",{"type":41,"tag":747,"props":1095,"children":1096},{"class":749,"line":785},[1097],{"type":41,"tag":747,"props":1098,"children":1099},{},[1100],{"type":47,"value":1101},"        SetStyle(ControlStyles.ApplyThemingImplicitly, true); \u002F\u002F opt-in; false = opt-out\n",{"type":41,"tag":747,"props":1103,"children":1104},{"class":749,"line":794},[1105],{"type":41,"tag":747,"props":1106,"children":1107},{},[1108],{"type":47,"value":1109},"        CreateParams cp = base.CreateParams;\n",{"type":41,"tag":747,"props":1111,"children":1112},{"class":749,"line":22},[1113],{"type":41,"tag":747,"props":1114,"children":1115},{},[1116],{"type":47,"value":1117},"        \u002F\u002F add WS_HSCROLL \u002F WS_VSCROLL here as needed\n",{"type":41,"tag":747,"props":1119,"children":1120},{"class":749,"line":812},[1121],{"type":41,"tag":747,"props":1122,"children":1123},{},[1124],{"type":47,"value":1125},"        return cp;\n",{"type":41,"tag":747,"props":1127,"children":1128},{"class":749,"line":821},[1129],{"type":41,"tag":747,"props":1130,"children":1131},{},[1132],{"type":47,"value":1133},"    }\n",{"type":41,"tag":747,"props":1135,"children":1136},{"class":749,"line":830},[1137],{"type":41,"tag":747,"props":1138,"children":1139},{},[1140],{"type":47,"value":845},{"type":41,"tag":50,"props":1142,"children":1143},{},[1144,1146,1151,1153,1158,1159,1164,1166,1171,1173,1179,1181,1185,1186,1192],{"type":47,"value":1145},"This ",{"type":41,"tag":122,"props":1147,"children":1148},{},[1149],{"type":47,"value":1150},"cannot",{"type":47,"value":1152}," be done in the constructor: the base constructor reads ",{"type":41,"tag":141,"props":1154,"children":1156},{"className":1155},[],[1157],{"type":47,"value":1053},{"type":47,"value":683},{"type":41,"tag":365,"props":1160,"children":1161},{},[1162],{"type":47,"value":1163},"before",{"type":47,"value":1165}," your constructor body runs. It must live in the ",{"type":41,"tag":141,"props":1167,"children":1169},{"className":1168},[],[1170],{"type":47,"value":1053},{"type":47,"value":1172}," getter, with the ",{"type":41,"tag":141,"props":1174,"children":1176},{"className":1175},[],[1177],{"type":47,"value":1178},"SetStyle",{"type":47,"value":1180}," call placed ",{"type":41,"tag":365,"props":1182,"children":1183},{},[1184],{"type":47,"value":1163},{"type":47,"value":683},{"type":41,"tag":141,"props":1187,"children":1189},{"className":1188},[],[1190],{"type":47,"value":1191},"base.CreateParams",{"type":47,"value":1193}," is read.",{"type":41,"tag":998,"props":1195,"children":1197},{"id":1196},"_42-systemcolors-flip-in-dark-mode-names-become-counter-intuitive",[1198,1200,1206],{"type":47,"value":1199},"4.2 ",{"type":41,"tag":141,"props":1201,"children":1203},{"className":1202},[],[1204],{"type":47,"value":1205},"SystemColors",{"type":47,"value":1207}," flip in dark mode ─ names become counter-intuitive",{"type":41,"tag":50,"props":1209,"children":1210},{},[1211,1213,1218,1220,1225,1227,1233,1235,1240],{"type":47,"value":1212},"In dark mode, ",{"type":41,"tag":141,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":47,"value":1205},{"type":47,"value":1219}," are remapped to roughly complementary values. The ",{"type":41,"tag":122,"props":1221,"children":1222},{},[1223],{"type":47,"value":1224},"name no longer matches the apparent brightness, and that is intentional",{"type":47,"value":1226},": ",{"type":41,"tag":141,"props":1228,"children":1230},{"className":1229},[],[1231],{"type":47,"value":1232},"ControlLightLight",{"type":47,"value":1234}," is very bright in classic mode and correspondingly dark in dark mode. The remap is ",{"type":41,"tag":365,"props":1236,"children":1237},{},[1238],{"type":47,"value":1239},"not",{"type":47,"value":1241}," always a strict mathematical complement ─ some colors are nudged to keep contrast adequate.",{"type":41,"tag":50,"props":1243,"children":1244},{},[1245],{"type":47,"value":1246},"Consequences:",{"type":41,"tag":68,"props":1248,"children":1249},{},[1250,1269,1302],{"type":41,"tag":72,"props":1251,"children":1252},{},[1253,1255,1260,1262,1267],{"type":47,"value":1254},"If you use ",{"type":41,"tag":141,"props":1256,"children":1258},{"className":1257},[],[1259],{"type":47,"value":1205},{"type":47,"value":1261},", accept that the name describes its ",{"type":41,"tag":365,"props":1263,"children":1264},{},[1265],{"type":47,"value":1266},"classic-mode",{"type":47,"value":1268}," role, not its color.",{"type":41,"tag":72,"props":1270,"children":1271},{},[1272,1274,1279,1281,1286,1288,1294,1296,1301],{"type":47,"value":1273},"For ",{"type":41,"tag":122,"props":1275,"children":1276},{},[1277],{"type":47,"value":1278},"guaranteed contrast in both modes",{"type":47,"value":1280},", don't use ",{"type":41,"tag":141,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":47,"value":1205},{"type":47,"value":1287}," for your control's palette. Define your own colors as explicit ",{"type":41,"tag":141,"props":1289,"children":1291},{"className":1290},[],[1292],{"type":47,"value":1293},"#AARRGGBB",{"type":47,"value":1295}," values with ",{"type":41,"tag":122,"props":1297,"children":1298},{},[1299],{"type":47,"value":1300},"separate defaults for classic and dark mode",{"type":47,"value":533},{"type":41,"tag":72,"props":1303,"children":1304},{},[1305,1307,1313,1315,1320],{"type":47,"value":1306},"Pick the active set at runtime via ",{"type":41,"tag":141,"props":1308,"children":1310},{"className":1309},[],[1311],{"type":47,"value":1312},"Application.IsDarkModeEnabled",{"type":47,"value":1314},", which reflects the ",{"type":41,"tag":365,"props":1316,"children":1317},{},[1318],{"type":47,"value":1319},"current",{"type":47,"value":1321}," mode:",{"type":41,"tag":736,"props":1323,"children":1325},{"className":738,"code":1324,"language":740,"meta":741,"style":741},"Color faceColor = Application.IsDarkModeEnabled\n    ? Color.FromArgb(unchecked((int)0xFF2D2D30))\n    : Color.FromArgb(unchecked((int)0xFFF0F0F0));\n",[1326],{"type":41,"tag":141,"props":1327,"children":1328},{"__ignoreMap":741},[1329,1337,1345],{"type":41,"tag":747,"props":1330,"children":1331},{"class":749,"line":26},[1332],{"type":41,"tag":747,"props":1333,"children":1334},{},[1335],{"type":47,"value":1336},"Color faceColor = Application.IsDarkModeEnabled\n",{"type":41,"tag":747,"props":1338,"children":1339},{"class":749,"line":758},[1340],{"type":41,"tag":747,"props":1341,"children":1342},{},[1343],{"type":47,"value":1344},"    ? Color.FromArgb(unchecked((int)0xFF2D2D30))\n",{"type":41,"tag":747,"props":1346,"children":1347},{"class":749,"line":767},[1348],{"type":41,"tag":747,"props":1349,"children":1350},{},[1351],{"type":47,"value":1352},"    : Color.FromArgb(unchecked((int)0xFFF0F0F0));\n",{"type":41,"tag":61,"props":1354,"children":1356},{"id":1355},"_5-usercontrols-composite-custom-controls",[1357],{"type":47,"value":1358},"5. UserControls & composite custom controls",{"type":41,"tag":50,"props":1360,"children":1361},{},[1362,1364,1369],{"type":47,"value":1363},"For a ",{"type":41,"tag":141,"props":1365,"children":1367},{"className":1366},[],[1368],{"type":47,"value":488},{"type":47,"value":1370}," (or any control composed of constituent controls):",{"type":41,"tag":68,"props":1372,"children":1373},{},[1374,1420,1443,1475],{"type":41,"tag":72,"props":1375,"children":1376},{},[1377,1390,1392,1397,1399,1405,1407,1412,1414,1419],{"type":41,"tag":122,"props":1378,"children":1379},{},[1380,1382,1388],{"type":47,"value":1381},"No design-time ",{"type":41,"tag":141,"props":1383,"children":1385},{"className":1384},[],[1386],{"type":47,"value":1387},"Font",{"type":47,"value":1389}," definitions.",{"type":47,"value":1391}," Don't set ",{"type":41,"tag":141,"props":1393,"children":1395},{"className":1394},[],[1396],{"type":47,"value":1387},{"type":47,"value":1398}," on the UserControl or its children at design time. Design-time fonts pollute the HighDPI ",{"type":41,"tag":141,"props":1400,"children":1402},{"className":1401},[],[1403],{"type":47,"value":1404},"AutoScaleDimensions",{"type":47,"value":1406}," code generation, so when the user later re-opens the control in the Designer the generated scaling code is wrong. Adjust font ",{"type":41,"tag":365,"props":1408,"children":1409},{},[1410],{"type":47,"value":1411},"size",{"type":47,"value":1413}," only at ",{"type":41,"tag":122,"props":1415,"children":1416},{},[1417],{"type":47,"value":1418},"runtime",{"type":47,"value":533},{"type":41,"tag":72,"props":1421,"children":1422},{},[1423,1434,1436,1441],{"type":41,"tag":122,"props":1424,"children":1425},{},[1426,1428],{"type":47,"value":1427},"Layout in a ",{"type":41,"tag":141,"props":1429,"children":1431},{"className":1430},[],[1432],{"type":47,"value":1433},"TableLayoutPanel",{"type":47,"value":1435}," with ",{"type":41,"tag":141,"props":1437,"children":1439},{"className":1438},[],[1440],{"type":47,"value":609},{"type":47,"value":1442}," rows\u002Fcolumns. Let the table compute geometry.",{"type":41,"tag":72,"props":1444,"children":1445},{},[1446,1456,1458,1466,1468,1473],{"type":41,"tag":122,"props":1447,"children":1448},{},[1449,1451],{"type":47,"value":1450},"The control itself exposes ",{"type":41,"tag":141,"props":1452,"children":1454},{"className":1453},[],[1455],{"type":47,"value":609},{"type":47,"value":1457}," and an honest ",{"type":41,"tag":122,"props":1459,"children":1460},{},[1461],{"type":41,"tag":141,"props":1462,"children":1464},{"className":1463},[],[1465],{"type":47,"value":625},{"type":47,"value":1467}," big enough to render every child unclipped across all HighDPI and large-font scenarios (§2). The ",{"type":41,"tag":141,"props":1469,"children":1471},{"className":1470},[],[1472],{"type":47,"value":1433},{"type":47,"value":1474}," with AutoSize cells does most of this for you, but verify the outer control reports it.",{"type":41,"tag":72,"props":1476,"children":1477},{},[1478,1483,1485,1490,1492,1498],{"type":41,"tag":122,"props":1479,"children":1480},{},[1481],{"type":47,"value":1482},"Very large UserControls",{"type":47,"value":1484}," with many containers\u002Fcontrols where a single clip-proof preferred size is impractical: host the content in a scrolling ",{"type":41,"tag":141,"props":1486,"children":1488},{"className":1487},[],[1489],{"type":47,"value":426},{"type":47,"value":1491}," (",{"type":41,"tag":141,"props":1493,"children":1495},{"className":1494},[],[1496],{"type":47,"value":1497},"AutoScroll = true",{"type":47,"value":1499},") rather than forcing an unreasonable minimum size.",{"type":41,"tag":61,"props":1501,"children":1503},{"id":1502},"_6-list-grid-like-controls",[1504],{"type":47,"value":1505},"6. List- \u002F Grid-like controls",{"type":41,"tag":50,"props":1507,"children":1508},{},[1509,1511,1521],{"type":47,"value":1510},"When asked for anything list- or grid-shaped, ",{"type":41,"tag":122,"props":1512,"children":1513},{},[1514,1516],{"type":47,"value":1515},"derive from ",{"type":41,"tag":141,"props":1517,"children":1519},{"className":1518},[],[1520],{"type":47,"value":505},{"type":47,"value":1522}," rather than building from scratch.",{"type":41,"tag":50,"props":1524,"children":1525},{},[1526,1528,1533,1535,1541],{"type":47,"value":1527},"For image-rich or graphically rich data records, the best outcome is usually to ",{"type":41,"tag":122,"props":1529,"children":1530},{},[1531],{"type":47,"value":1532},"render the entire data item in one cell",{"type":47,"value":1534}," via a custom ",{"type":41,"tag":141,"props":1536,"children":1538},{"className":1537},[],[1539],{"type":47,"value":1540},"DataGridViewCell",{"type":47,"value":1542}," ─ symbol fonts, multiple colors, multiple font sizes, multi-line layout, all in a single cell. Skip column headers in that case.",{"type":41,"tag":50,"props":1544,"children":1545},{},[1546,1548,1553],{"type":47,"value":1547},"Keep column headers (and therefore per-field columns) only when the context genuinely needs a schema overview or per-column sort\u002Ffilter. Even then, prefer ",{"type":41,"tag":122,"props":1549,"children":1550},{},[1551],{"type":47,"value":1552},"custom cell rendering",{"type":47,"value":1554}," to get the rich graphical UI; don't fall back to plain text just because headers exist.",{"type":41,"tag":50,"props":1556,"children":1557},{},[1558,1560,1565],{"type":47,"value":1559},"Whenever cells vary in height, ",{"type":41,"tag":122,"props":1561,"children":1562},{},[1563],{"type":47,"value":1564},"compute row height from the tallest cell in the data row",{"type":47,"value":1566}," ─ measure each cell's required height and set the row to the max, or the content clips.",{"type":41,"tag":61,"props":1568,"children":1570},{"id":1569},"_7-designer-serialization-for-new-properties",[1571],{"type":47,"value":1572},"7. Designer serialization for new properties",{"type":41,"tag":50,"props":1574,"children":1575},{},[1576,1578,1583],{"type":47,"value":1577},"Every public property you add must tell the Designer how to serialize it. Pick ",{"type":41,"tag":122,"props":1579,"children":1580},{},[1581],{"type":47,"value":1582},"exactly one",{"type":47,"value":1584}," of these three mechanisms (they conflict if combined):",{"type":41,"tag":1586,"props":1587,"children":1588},"ol",{},[1589,1626,1640],{"type":41,"tag":72,"props":1590,"children":1591},{},[1592,1601,1602,1608,1610,1616,1618,1624],{"type":41,"tag":122,"props":1593,"children":1594},{},[1595],{"type":41,"tag":141,"props":1596,"children":1598},{"className":1597},[],[1599],{"type":47,"value":1600},"[DesignerSerializationVisibility(...)]",{"type":47,"value":160},{"type":41,"tag":141,"props":1603,"children":1605},{"className":1604},[],[1606],{"type":47,"value":1607},"Hidden",{"type":47,"value":1609}," for runtime-only\u002Fderived properties the Designer must not write to ",{"type":41,"tag":141,"props":1611,"children":1613},{"className":1612},[],[1614],{"type":47,"value":1615},"InitializeComponent",{"type":47,"value":1617},"; ",{"type":41,"tag":141,"props":1619,"children":1621},{"className":1620},[],[1622],{"type":47,"value":1623},"Content",{"type":47,"value":1625}," for collections whose items serialize individually.",{"type":41,"tag":72,"props":1627,"children":1628},{},[1629,1638],{"type":41,"tag":122,"props":1630,"children":1631},{},[1632],{"type":41,"tag":141,"props":1633,"children":1635},{"className":1634},[],[1636],{"type":47,"value":1637},"[DefaultValue(...)]",{"type":47,"value":1639}," ─ the property serializes only when its value differs from this constant. Use for simple properties with a fixed, compile-time-constant default.",{"type":41,"tag":72,"props":1641,"children":1642},{},[1643,1662,1663,1669,1671,1677,1679,1684,1686,1691,1693,1699],{"type":41,"tag":122,"props":1644,"children":1645},{},[1646,1652,1654,1660],{"type":41,"tag":141,"props":1647,"children":1649},{"className":1648},[],[1650],{"type":47,"value":1651},"ResetXxx()",{"type":47,"value":1653}," + ",{"type":41,"tag":141,"props":1655,"children":1657},{"className":1656},[],[1658],{"type":47,"value":1659},"ShouldSerializeXxx()",{"type":47,"value":1661}," pair",{"type":47,"value":160},{"type":41,"tag":141,"props":1664,"children":1666},{"className":1665},[],[1667],{"type":47,"value":1668},"ShouldSerializeXxx",{"type":47,"value":1670}," returns whether the value should be written; ",{"type":41,"tag":141,"props":1672,"children":1674},{"className":1673},[],[1675],{"type":47,"value":1676},"ResetXxx",{"type":47,"value":1678}," restores the default. ",{"type":41,"tag":122,"props":1680,"children":1681},{},[1682],{"type":47,"value":1683},"Use this",{"type":47,"value":1685}," for ambient properties, and whenever a default is ",{"type":41,"tag":365,"props":1687,"children":1688},{},[1689],{"type":47,"value":1690},"not constant",{"type":47,"value":1692}," (depends on another property or the theme) ─ ",{"type":41,"tag":141,"props":1694,"children":1696},{"className":1695},[],[1697],{"type":47,"value":1698},"[DefaultValue]",{"type":47,"value":1700}," can't express that.",{"type":41,"tag":50,"props":1702,"children":1703},{},[1704],{"type":47,"value":1705},"The method pair, for a property whose default depends on the current theme:",{"type":41,"tag":736,"props":1707,"children":1709},{"className":738,"code":1708,"language":740,"meta":741,"style":741},"\u002F\u002F\u002F \u003Csummary>Gets or sets the color of the control's face.\u003C\u002Fsummary>\npublic Color FaceColor { get; set; } = DefaultFaceColor;\n\nprivate static Color DefaultFaceColor\n    => Application.IsDarkModeEnabled\n        ? Color.FromArgb(unchecked((int)0xFF2D2D30))\n        : Color.FromArgb(unchecked((int)0xFFF0F0F0));\n\n\u002F\u002F The Designer discovers these by naming convention ─ keep them private.\nprivate bool ShouldSerializeFaceColor()\n    => FaceColor != DefaultFaceColor;\n\nprivate void ResetFaceColor()\n    => FaceColor = DefaultFaceColor;\n",[1710],{"type":41,"tag":141,"props":1711,"children":1712},{"__ignoreMap":741},[1713,1721,1729,1736,1744,1752,1760,1768,1775,1783,1791,1799,1807,1816],{"type":41,"tag":747,"props":1714,"children":1715},{"class":749,"line":26},[1716],{"type":41,"tag":747,"props":1717,"children":1718},{},[1719],{"type":47,"value":1720},"\u002F\u002F\u002F \u003Csummary>Gets or sets the color of the control's face.\u003C\u002Fsummary>\n",{"type":41,"tag":747,"props":1722,"children":1723},{"class":749,"line":758},[1724],{"type":41,"tag":747,"props":1725,"children":1726},{},[1727],{"type":47,"value":1728},"public Color FaceColor { get; set; } = DefaultFaceColor;\n",{"type":41,"tag":747,"props":1730,"children":1731},{"class":749,"line":767},[1732],{"type":41,"tag":747,"props":1733,"children":1734},{"emptyLinePlaceholder":806},[1735],{"type":47,"value":809},{"type":41,"tag":747,"props":1737,"children":1738},{"class":749,"line":776},[1739],{"type":41,"tag":747,"props":1740,"children":1741},{},[1742],{"type":47,"value":1743},"private static Color DefaultFaceColor\n",{"type":41,"tag":747,"props":1745,"children":1746},{"class":749,"line":785},[1747],{"type":41,"tag":747,"props":1748,"children":1749},{},[1750],{"type":47,"value":1751},"    => Application.IsDarkModeEnabled\n",{"type":41,"tag":747,"props":1753,"children":1754},{"class":749,"line":794},[1755],{"type":41,"tag":747,"props":1756,"children":1757},{},[1758],{"type":47,"value":1759},"        ? Color.FromArgb(unchecked((int)0xFF2D2D30))\n",{"type":41,"tag":747,"props":1761,"children":1762},{"class":749,"line":22},[1763],{"type":41,"tag":747,"props":1764,"children":1765},{},[1766],{"type":47,"value":1767},"        : Color.FromArgb(unchecked((int)0xFFF0F0F0));\n",{"type":41,"tag":747,"props":1769,"children":1770},{"class":749,"line":812},[1771],{"type":41,"tag":747,"props":1772,"children":1773},{"emptyLinePlaceholder":806},[1774],{"type":47,"value":809},{"type":41,"tag":747,"props":1776,"children":1777},{"class":749,"line":821},[1778],{"type":41,"tag":747,"props":1779,"children":1780},{},[1781],{"type":47,"value":1782},"\u002F\u002F The Designer discovers these by naming convention ─ keep them private.\n",{"type":41,"tag":747,"props":1784,"children":1785},{"class":749,"line":830},[1786],{"type":41,"tag":747,"props":1787,"children":1788},{},[1789],{"type":47,"value":1790},"private bool ShouldSerializeFaceColor()\n",{"type":41,"tag":747,"props":1792,"children":1793},{"class":749,"line":839},[1794],{"type":41,"tag":747,"props":1795,"children":1796},{},[1797],{"type":47,"value":1798},"    => FaceColor != DefaultFaceColor;\n",{"type":41,"tag":747,"props":1800,"children":1802},{"class":749,"line":1801},12,[1803],{"type":41,"tag":747,"props":1804,"children":1805},{"emptyLinePlaceholder":806},[1806],{"type":47,"value":809},{"type":41,"tag":747,"props":1808,"children":1810},{"class":749,"line":1809},13,[1811],{"type":41,"tag":747,"props":1812,"children":1813},{},[1814],{"type":47,"value":1815},"private void ResetFaceColor()\n",{"type":41,"tag":747,"props":1817,"children":1819},{"class":749,"line":1818},14,[1820],{"type":41,"tag":747,"props":1821,"children":1822},{},[1823],{"type":47,"value":1824},"    => FaceColor = DefaultFaceColor;\n",{"type":41,"tag":50,"props":1826,"children":1827},{},[1828,1830,1836,1838,1844,1845,1851,1853,1858],{"type":47,"value":1829},"Note the convention: the methods are ",{"type":41,"tag":141,"props":1831,"children":1833},{"className":1832},[],[1834],{"type":47,"value":1835},"private",{"type":47,"value":1837},", named exactly ",{"type":41,"tag":141,"props":1839,"children":1841},{"className":1840},[],[1842],{"type":47,"value":1843},"ShouldSerialize\u003CProperty>",{"type":47,"value":168},{"type":41,"tag":141,"props":1846,"children":1848},{"className":1847},[],[1849],{"type":47,"value":1850},"Reset\u003CProperty>",{"type":47,"value":1852},", and take no parameters. Don't combine them with ",{"type":41,"tag":141,"props":1854,"children":1856},{"className":1855},[],[1857],{"type":47,"value":1698},{"type":47,"value":1859}," on the same property ─ the two mechanisms conflict.",{"type":41,"tag":50,"props":1861,"children":1862},{},[1863],{"type":47,"value":1864},"Don't leave a property with none of these ─ the Designer will either over-serialize or fail to round-trip.",{"type":41,"tag":998,"props":1866,"children":1868},{"id":1867},"_71-property-window-attributes",[1869],{"type":47,"value":1870},"7.1 Property-window attributes",{"type":41,"tag":50,"props":1872,"children":1873},{},[1874,1876,1881],{"type":47,"value":1875},"Beyond serialization, decorate every new public property so it behaves well in the Properties window and IntelliSense. These are four ",{"type":41,"tag":365,"props":1877,"children":1878},{},[1879],{"type":47,"value":1880},"distinct",{"type":47,"value":1882}," concerns:",{"type":41,"tag":68,"props":1884,"children":1885},{},[1886,1929,1949,1977],{"type":41,"tag":72,"props":1887,"children":1888},{},[1889,1898,1900,1906,1907,1913,1914,1920,1921,1927],{"type":41,"tag":122,"props":1890,"children":1891},{},[1892],{"type":41,"tag":141,"props":1893,"children":1895},{"className":1894},[],[1896],{"type":47,"value":1897},"[Category(\"Appearance\")]",{"type":47,"value":1899}," ─ the Properties-window group. Reuse standard names (",{"type":41,"tag":141,"props":1901,"children":1903},{"className":1902},[],[1904],{"type":47,"value":1905},"Appearance",{"type":47,"value":266},{"type":41,"tag":141,"props":1908,"children":1910},{"className":1909},[],[1911],{"type":47,"value":1912},"Behavior",{"type":47,"value":266},{"type":41,"tag":141,"props":1915,"children":1917},{"className":1916},[],[1918],{"type":47,"value":1919},"Layout",{"type":47,"value":266},{"type":41,"tag":141,"props":1922,"children":1924},{"className":1923},[],[1925],{"type":47,"value":1926},"Data",{"type":47,"value":1928},", —¦) so your properties merge with the built-in ones.",{"type":41,"tag":72,"props":1930,"children":1931},{},[1932,1941,1943,1948],{"type":41,"tag":122,"props":1933,"children":1934},{},[1935],{"type":41,"tag":141,"props":1936,"children":1938},{"className":1937},[],[1939],{"type":47,"value":1940},"[Description(\"...\")]",{"type":47,"value":1942}," ─ help text in the Properties window's description pane. Write it for a control ",{"type":41,"tag":365,"props":1944,"children":1945},{},[1946],{"type":47,"value":1947},"consumer",{"type":47,"value":533},{"type":41,"tag":72,"props":1950,"children":1951},{},[1952,1961,1963,1969,1971,1975],{"type":41,"tag":122,"props":1953,"children":1954},{},[1955],{"type":41,"tag":141,"props":1956,"children":1958},{"className":1957},[],[1959],{"type":47,"value":1960},"[Browsable(false)]",{"type":47,"value":1962}," ─ hides the property from the Properties window. Use for runtime-only state. It almost always also needs ",{"type":41,"tag":141,"props":1964,"children":1966},{"className":1965},[],[1967],{"type":47,"value":1968},"[DesignerSerializationVisibility(Hidden)]",{"type":47,"value":1970}," ─ hiding from the grid does ",{"type":41,"tag":365,"props":1972,"children":1973},{},[1974],{"type":47,"value":1239},{"type":47,"value":1976}," stop serialization.",{"type":41,"tag":72,"props":1978,"children":1979},{},[1980,1989,1991,1997,1999,2005],{"type":41,"tag":122,"props":1981,"children":1982},{},[1983],{"type":41,"tag":141,"props":1984,"children":1986},{"className":1985},[],[1987],{"type":47,"value":1988},"[EditorBrowsable(EditorBrowsableState.Never | Advanced)]",{"type":47,"value":1990}," ─ controls IntelliSense visibility, independent of the grid. ",{"type":41,"tag":141,"props":1992,"children":1994},{"className":1993},[],[1995],{"type":47,"value":1996},"Never",{"type":47,"value":1998}," hides from completion; ",{"type":41,"tag":141,"props":2000,"children":2002},{"className":2001},[],[2003],{"type":47,"value":2004},"Advanced",{"type":47,"value":2006}," shows only when \"Hide advanced members\" is off.",{"type":41,"tag":50,"props":2008,"children":2009},{},[2010,2012,2018,2020,2026,2027,2033],{"type":47,"value":2011},"To fully suppress an inherited property that's meaningless on your control (e.g. shadowing ",{"type":41,"tag":141,"props":2013,"children":2015},{"className":2014},[],[2016],{"type":47,"value":2017},"Text",{"type":47,"value":2019},"), combine all three on the ",{"type":41,"tag":141,"props":2021,"children":2023},{"className":2022},[],[2024],{"type":47,"value":2025},"new",{"type":47,"value":194},{"type":41,"tag":141,"props":2028,"children":2030},{"className":2029},[],[2031],{"type":47,"value":2032},"override",{"type":47,"value":2034}," member:",{"type":41,"tag":736,"props":2036,"children":2038},{"className":738,"code":2037,"language":740,"meta":741,"style":741},"[Browsable(false)]\n[EditorBrowsable(EditorBrowsableState.Never)]\n[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\npublic override string Text\n{\n    get => base.Text;\n    set => base.Text = value;\n}\n",[2039],{"type":41,"tag":141,"props":2040,"children":2041},{"__ignoreMap":741},[2042,2050,2058,2066,2074,2081,2089,2097],{"type":41,"tag":747,"props":2043,"children":2044},{"class":749,"line":26},[2045],{"type":41,"tag":747,"props":2046,"children":2047},{},[2048],{"type":47,"value":2049},"[Browsable(false)]\n",{"type":41,"tag":747,"props":2051,"children":2052},{"class":749,"line":758},[2053],{"type":41,"tag":747,"props":2054,"children":2055},{},[2056],{"type":47,"value":2057},"[EditorBrowsable(EditorBrowsableState.Never)]\n",{"type":41,"tag":747,"props":2059,"children":2060},{"class":749,"line":767},[2061],{"type":41,"tag":747,"props":2062,"children":2063},{},[2064],{"type":47,"value":2065},"[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\n",{"type":41,"tag":747,"props":2067,"children":2068},{"class":749,"line":776},[2069],{"type":41,"tag":747,"props":2070,"children":2071},{},[2072],{"type":47,"value":2073},"public override string Text\n",{"type":41,"tag":747,"props":2075,"children":2076},{"class":749,"line":785},[2077],{"type":41,"tag":747,"props":2078,"children":2079},{},[2080],{"type":47,"value":764},{"type":41,"tag":747,"props":2082,"children":2083},{"class":749,"line":794},[2084],{"type":41,"tag":747,"props":2085,"children":2086},{},[2087],{"type":47,"value":2088},"    get => base.Text;\n",{"type":41,"tag":747,"props":2090,"children":2091},{"class":749,"line":22},[2092],{"type":41,"tag":747,"props":2093,"children":2094},{},[2095],{"type":47,"value":2096},"    set => base.Text = value;\n",{"type":41,"tag":747,"props":2098,"children":2099},{"class":749,"line":812},[2100],{"type":41,"tag":747,"props":2101,"children":2102},{},[2103],{"type":47,"value":845},{"type":41,"tag":50,"props":2105,"children":2106},{},[2107],{"type":47,"value":2108},"A normal, visible property reads like this:",{"type":41,"tag":736,"props":2110,"children":2112},{"className":738,"code":2111,"language":740,"meta":741,"style":741},"[Category(\"Appearance\")]\n[Description(\"The color used to paint the control's face.\")]\npublic Color FaceColor { get; set; } = DefaultFaceColor;\n",[2113],{"type":41,"tag":141,"props":2114,"children":2115},{"__ignoreMap":741},[2116,2124,2132],{"type":41,"tag":747,"props":2117,"children":2118},{"class":749,"line":26},[2119],{"type":41,"tag":747,"props":2120,"children":2121},{},[2122],{"type":47,"value":2123},"[Category(\"Appearance\")]\n",{"type":41,"tag":747,"props":2125,"children":2126},{"class":749,"line":758},[2127],{"type":41,"tag":747,"props":2128,"children":2129},{},[2130],{"type":47,"value":2131},"[Description(\"The color used to paint the control's face.\")]\n",{"type":41,"tag":747,"props":2133,"children":2134},{"class":749,"line":767},[2135],{"type":41,"tag":747,"props":2136,"children":2137},{},[2138],{"type":47,"value":1728},{"type":41,"tag":61,"props":2140,"children":2142},{"id":2141},"_8-construction-order-isupportinitialize",[2143,2145],{"type":47,"value":2144},"8. Construction order ─ ",{"type":41,"tag":141,"props":2146,"children":2148},{"className":2147},[],[2149],{"type":47,"value":2150},"ISupportInitialize",{"type":41,"tag":50,"props":2152,"children":2153},{},[2154,2156,2161,2163,2168],{"type":47,"value":2155},"During ",{"type":41,"tag":141,"props":2157,"children":2159},{"className":2158},[],[2160],{"type":47,"value":1615},{"type":47,"value":2162},", the Designer sets your properties one at a time in an order ",{"type":41,"tag":365,"props":2164,"children":2165},{},[2166],{"type":47,"value":2167},"you don't control",{"type":47,"value":2169},". If two properties are interdependent ─ or a setter does expensive work (re-layout, allocation, a Win32 round-trip) ─ the control repeats that work against a half-configured state, and may even throw because property B isn't set yet when property A's setter runs.",{"type":41,"tag":50,"props":2171,"children":2172},{},[2173,2175,2183,2185,2191,2193,2199],{"type":47,"value":2174},"Implement ",{"type":41,"tag":122,"props":2176,"children":2177},{},[2178],{"type":41,"tag":141,"props":2179,"children":2181},{"className":2180},[],[2182],{"type":47,"value":2150},{"type":47,"value":2184}," to defer it. The Designer emits ",{"type":41,"tag":141,"props":2186,"children":2188},{"className":2187},[],[2189],{"type":47,"value":2190},"BeginInit()",{"type":47,"value":2192}," before the property block and ",{"type":41,"tag":141,"props":2194,"children":2196},{"className":2195},[],[2197],{"type":47,"value":2198},"EndInit()",{"type":47,"value":2200}," after; do nothing expensive in between:",{"type":41,"tag":736,"props":2202,"children":2204},{"className":738,"code":2203,"language":740,"meta":741,"style":741},"public class GaugeControl : Control, ISupportInitialize\n{\n    private bool _initializing;\n\n    public void BeginInit()\n        => _initializing = true;\n\n    public void EndInit()\n    {\n        _initializing = false;\n        RecalculateLayout(); \u002F\u002F the deferred work, done once, fully configured\n        Invalidate();\n    }\n\n    public int Minimum\n    {\n        get;\n        set\n        {\n            field = value;\n\n            if (!_initializing)\n            {\n                RecalculateLayout();\n                Invalidate();\n            }\n        }\n    }\n}\n",[2205],{"type":41,"tag":141,"props":2206,"children":2207},{"__ignoreMap":741},[2208,2216,2223,2231,2238,2246,2254,2261,2269,2276,2284,2292,2300,2307,2314,2323,2331,2340,2349,2358,2367,2375,2384,2393,2402,2411,2420,2429,2437],{"type":41,"tag":747,"props":2209,"children":2210},{"class":749,"line":26},[2211],{"type":41,"tag":747,"props":2212,"children":2213},{},[2214],{"type":47,"value":2215},"public class GaugeControl : Control, ISupportInitialize\n",{"type":41,"tag":747,"props":2217,"children":2218},{"class":749,"line":758},[2219],{"type":41,"tag":747,"props":2220,"children":2221},{},[2222],{"type":47,"value":764},{"type":41,"tag":747,"props":2224,"children":2225},{"class":749,"line":767},[2226],{"type":41,"tag":747,"props":2227,"children":2228},{},[2229],{"type":47,"value":2230},"    private bool _initializing;\n",{"type":41,"tag":747,"props":2232,"children":2233},{"class":749,"line":776},[2234],{"type":41,"tag":747,"props":2235,"children":2236},{"emptyLinePlaceholder":806},[2237],{"type":47,"value":809},{"type":41,"tag":747,"props":2239,"children":2240},{"class":749,"line":785},[2241],{"type":41,"tag":747,"props":2242,"children":2243},{},[2244],{"type":47,"value":2245},"    public void BeginInit()\n",{"type":41,"tag":747,"props":2247,"children":2248},{"class":749,"line":794},[2249],{"type":41,"tag":747,"props":2250,"children":2251},{},[2252],{"type":47,"value":2253},"        => _initializing = true;\n",{"type":41,"tag":747,"props":2255,"children":2256},{"class":749,"line":22},[2257],{"type":41,"tag":747,"props":2258,"children":2259},{"emptyLinePlaceholder":806},[2260],{"type":47,"value":809},{"type":41,"tag":747,"props":2262,"children":2263},{"class":749,"line":812},[2264],{"type":41,"tag":747,"props":2265,"children":2266},{},[2267],{"type":47,"value":2268},"    public void EndInit()\n",{"type":41,"tag":747,"props":2270,"children":2271},{"class":749,"line":821},[2272],{"type":41,"tag":747,"props":2273,"children":2274},{},[2275],{"type":47,"value":1093},{"type":41,"tag":747,"props":2277,"children":2278},{"class":749,"line":830},[2279],{"type":41,"tag":747,"props":2280,"children":2281},{},[2282],{"type":47,"value":2283},"        _initializing = false;\n",{"type":41,"tag":747,"props":2285,"children":2286},{"class":749,"line":839},[2287],{"type":41,"tag":747,"props":2288,"children":2289},{},[2290],{"type":47,"value":2291},"        RecalculateLayout(); \u002F\u002F the deferred work, done once, fully configured\n",{"type":41,"tag":747,"props":2293,"children":2294},{"class":749,"line":1801},[2295],{"type":41,"tag":747,"props":2296,"children":2297},{},[2298],{"type":47,"value":2299},"        Invalidate();\n",{"type":41,"tag":747,"props":2301,"children":2302},{"class":749,"line":1809},[2303],{"type":41,"tag":747,"props":2304,"children":2305},{},[2306],{"type":47,"value":1133},{"type":41,"tag":747,"props":2308,"children":2309},{"class":749,"line":1818},[2310],{"type":41,"tag":747,"props":2311,"children":2312},{"emptyLinePlaceholder":806},[2313],{"type":47,"value":809},{"type":41,"tag":747,"props":2315,"children":2317},{"class":749,"line":2316},15,[2318],{"type":41,"tag":747,"props":2319,"children":2320},{},[2321],{"type":47,"value":2322},"    public int Minimum\n",{"type":41,"tag":747,"props":2324,"children":2326},{"class":749,"line":2325},16,[2327],{"type":41,"tag":747,"props":2328,"children":2329},{},[2330],{"type":47,"value":1093},{"type":41,"tag":747,"props":2332,"children":2334},{"class":749,"line":2333},17,[2335],{"type":41,"tag":747,"props":2336,"children":2337},{},[2338],{"type":47,"value":2339},"        get;\n",{"type":41,"tag":747,"props":2341,"children":2343},{"class":749,"line":2342},18,[2344],{"type":41,"tag":747,"props":2345,"children":2346},{},[2347],{"type":47,"value":2348},"        set\n",{"type":41,"tag":747,"props":2350,"children":2352},{"class":749,"line":2351},19,[2353],{"type":41,"tag":747,"props":2354,"children":2355},{},[2356],{"type":47,"value":2357},"        {\n",{"type":41,"tag":747,"props":2359,"children":2361},{"class":749,"line":2360},20,[2362],{"type":41,"tag":747,"props":2363,"children":2364},{},[2365],{"type":47,"value":2366},"            field = value;\n",{"type":41,"tag":747,"props":2368,"children":2370},{"class":749,"line":2369},21,[2371],{"type":41,"tag":747,"props":2372,"children":2373},{"emptyLinePlaceholder":806},[2374],{"type":47,"value":809},{"type":41,"tag":747,"props":2376,"children":2378},{"class":749,"line":2377},22,[2379],{"type":41,"tag":747,"props":2380,"children":2381},{},[2382],{"type":47,"value":2383},"            if (!_initializing)\n",{"type":41,"tag":747,"props":2385,"children":2387},{"class":749,"line":2386},23,[2388],{"type":41,"tag":747,"props":2389,"children":2390},{},[2391],{"type":47,"value":2392},"            {\n",{"type":41,"tag":747,"props":2394,"children":2396},{"class":749,"line":2395},24,[2397],{"type":41,"tag":747,"props":2398,"children":2399},{},[2400],{"type":47,"value":2401},"                RecalculateLayout();\n",{"type":41,"tag":747,"props":2403,"children":2405},{"class":749,"line":2404},25,[2406],{"type":41,"tag":747,"props":2407,"children":2408},{},[2409],{"type":47,"value":2410},"                Invalidate();\n",{"type":41,"tag":747,"props":2412,"children":2414},{"class":749,"line":2413},26,[2415],{"type":41,"tag":747,"props":2416,"children":2417},{},[2418],{"type":47,"value":2419},"            }\n",{"type":41,"tag":747,"props":2421,"children":2423},{"class":749,"line":2422},27,[2424],{"type":41,"tag":747,"props":2425,"children":2426},{},[2427],{"type":47,"value":2428},"        }\n",{"type":41,"tag":747,"props":2430,"children":2432},{"class":749,"line":2431},28,[2433],{"type":41,"tag":747,"props":2434,"children":2435},{},[2436],{"type":47,"value":1133},{"type":41,"tag":747,"props":2438,"children":2440},{"class":749,"line":2439},29,[2441],{"type":41,"tag":747,"props":2442,"children":2443},{},[2444],{"type":47,"value":845},{"type":41,"tag":50,"props":2446,"children":2447},{},[2448,2450,2456,2458,2463,2465,2471,2473,2479,2480,2485,2487,2492,2494,2500],{"type":47,"value":2449},"Every interdependent setter checks ",{"type":41,"tag":141,"props":2451,"children":2453},{"className":2452},[],[2454],{"type":47,"value":2455},"_initializing",{"type":47,"value":2457}," and skips the expensive path while it's ",{"type":41,"tag":141,"props":2459,"children":2461},{"className":2460},[],[2462],{"type":47,"value":617},{"type":47,"value":2464},". ",{"type":41,"tag":141,"props":2466,"children":2468},{"className":2467},[],[2469],{"type":47,"value":2470},"EndInit",{"type":47,"value":2472}," runs that path exactly once. At runtime (no Designer), code that sets properties directly without calling ",{"type":41,"tag":141,"props":2474,"children":2476},{"className":2475},[],[2477],{"type":47,"value":2478},"BeginInit",{"type":47,"value":194},{"type":41,"tag":141,"props":2481,"children":2483},{"className":2482},[],[2484],{"type":47,"value":2470},{"type":47,"value":2486}," still works ─ ",{"type":41,"tag":141,"props":2488,"children":2490},{"className":2489},[],[2491],{"type":47,"value":2455},{"type":47,"value":2493}," is just ",{"type":41,"tag":141,"props":2495,"children":2497},{"className":2496},[],[2498],{"type":47,"value":2499},"false",{"type":47,"value":2501},", so each setter does its work immediately.",{"type":41,"tag":61,"props":2503,"children":2505},{"id":2504},"_9-designer-support-code-net-6",[2506],{"type":47,"value":2507},"9. Designer support code (.NET 6+)",{"type":41,"tag":50,"props":2509,"children":2510},{},[2511,2513,2518],{"type":47,"value":2512},"Designer functionality in .NET 6+ requires the ",{"type":41,"tag":122,"props":2514,"children":2515},{},[2516],{"type":47,"value":2517},"WinForms Designer SDK",{"type":47,"value":2519}," NuGet package.",{"type":41,"tag":68,"props":2521,"children":2522},{},[2523,2547,2590],{"type":41,"tag":72,"props":2524,"children":2525},{},[2526,2528,2537,2539,2545],{"type":47,"value":2527},"Use the current preview: ",{"type":41,"tag":122,"props":2529,"children":2530},{},[2531],{"type":41,"tag":141,"props":2532,"children":2534},{"className":2533},[],[2535],{"type":47,"value":2536},"Microsoft.WinForms.Designer.SDK 1.13.0-preview.2.24575.3",{"type":47,"value":2538},". The latest stable (",{"type":41,"tag":141,"props":2540,"children":2542},{"className":2541},[],[2543],{"type":47,"value":2544},"1.6.0",{"type":47,"value":2546},") is missing features you'll likely need ─ prefer the preview.",{"type":41,"tag":72,"props":2548,"children":2549},{},[2550,2552,2557,2559,2564,2566,2572,2574,2580,2582,2588],{"type":47,"value":2551},"Without shipping a separate Designer NuGet package, you ",{"type":41,"tag":122,"props":2553,"children":2554},{},[2555],{"type":47,"value":2556},"can",{"type":47,"value":2558}," put the following in the ",{"type":41,"tag":365,"props":2560,"children":2561},{},[2562],{"type":47,"value":2563},"same .NET assembly as the control",{"type":47,"value":2565},": custom ",{"type":41,"tag":141,"props":2567,"children":2569},{"className":2568},[],[2570],{"type":47,"value":2571},"CodeDomSerializer",{"type":47,"value":2573},"s, custom ",{"type":41,"tag":141,"props":2575,"children":2577},{"className":2576},[],[2578],{"type":47,"value":2579},"TypeConverter",{"type":47,"value":2581},"s, and custom ",{"type":41,"tag":141,"props":2583,"children":2585},{"className":2584},[],[2586],{"type":47,"value":2587},"DesignerActionList",{"type":47,"value":2589}," (smart-tag) actions.",{"type":41,"tag":72,"props":2591,"children":2592},{},[2593,2598,2600,2605],{"type":41,"tag":122,"props":2594,"children":2595},{},[2596],{"type":47,"value":2597},"Out of scope for this skill:",{"type":47,"value":2599}," Designers with a ",{"type":41,"tag":365,"props":2601,"children":2602},{},[2603],{"type":47,"value":2604},"custom design-time UI",{"type":47,"value":2606},". Those can't live in the control assembly ─ they need a dedicated multi-assembly NuGet package (client side on .NET Framework 4.7.2, server-side process on .NET, and a multi-targeted communication layer). If the user needs that, say so and stop.",{"type":41,"tag":61,"props":2608,"children":2610},{"id":2609},"quick-checklist",[2611],{"type":47,"value":2612},"Quick checklist",{"type":41,"tag":68,"props":2614,"children":2615},{},[2616,2642,2665,2684,2716,2735,2781,2800],{"type":41,"tag":72,"props":2617,"children":2618},{},[2619,2621,2626,2628,2633,2635,2640],{"type":47,"value":2620},"Most specific base class (",{"type":41,"tag":141,"props":2622,"children":2624},{"className":2623},[],[2625],{"type":47,"value":397},{"type":47,"value":2627}," generic, ",{"type":41,"tag":141,"props":2629,"children":2631},{"className":2630},[],[2632],{"type":47,"value":488},{"type":47,"value":2634}," composite, ",{"type":41,"tag":141,"props":2636,"children":2638},{"className":2637},[],[2639],{"type":47,"value":505},{"type":47,"value":2641}," list\u002Fgrid).",{"type":41,"tag":72,"props":2643,"children":2644},{},[2645,2650,2652,2657,2658,2663],{"type":41,"tag":141,"props":2646,"children":2648},{"className":2647},[],[2649],{"type":47,"value":625},{"type":47,"value":2651}," honest; ",{"type":41,"tag":141,"props":2653,"children":2655},{"className":2654},[],[2656],{"type":47,"value":609},{"type":47,"value":1653},{"type":41,"tag":141,"props":2659,"children":2661},{"className":2660},[],[2662],{"type":47,"value":675},{"type":47,"value":2664}," honored; survives 200% DPI \u002F large fonts.",{"type":41,"tag":72,"props":2666,"children":2667},{},[2668,2670,2676,2678,2683],{"type":47,"value":2669},"Owner-draw → ",{"type":41,"tag":141,"props":2671,"children":2673},{"className":2672},[],[2674],{"type":47,"value":2675},"OptimizedDoubleBuffer | AllPaintingInWmPaint | UserPaint",{"type":47,"value":2677},"; repaint via ",{"type":41,"tag":141,"props":2679,"children":2681},{"className":2680},[],[2682],{"type":47,"value":640},{"type":47,"value":533},{"type":41,"tag":72,"props":2685,"children":2686},{},[2687,2689,2694,2696,2701,2703,2708,2709,2715],{"type":47,"value":2688},"Dark mode: own ",{"type":41,"tag":141,"props":2690,"children":2692},{"className":2691},[],[2693],{"type":47,"value":1293},{"type":47,"value":2695}," palette per mode, switched on ",{"type":41,"tag":141,"props":2697,"children":2699},{"className":2698},[],[2700],{"type":47,"value":1312},{"type":47,"value":2702},"; Win32 scrollbars themed via ",{"type":41,"tag":141,"props":2704,"children":2706},{"className":2705},[],[2707],{"type":47,"value":1053},{"type":47,"value":1653},{"type":41,"tag":141,"props":2710,"children":2712},{"className":2711},[],[2713],{"type":47,"value":2714},"ApplyThemingImplicitly",{"type":47,"value":533},{"type":41,"tag":72,"props":2717,"children":2718},{},[2719,2721,2726,2728,2733],{"type":47,"value":2720},"UserControl: no design-time fonts, ",{"type":41,"tag":141,"props":2722,"children":2724},{"className":2723},[],[2725],{"type":47,"value":1433},{"type":47,"value":2727}," with AutoSize cells, scrolling ",{"type":41,"tag":141,"props":2729,"children":2731},{"className":2730},[],[2732],{"type":47,"value":426},{"type":47,"value":2734}," if too large.",{"type":41,"tag":72,"props":2736,"children":2737},{},[2738,2740,2745,2746,2752,2754,2759,2760,2765,2767,2773,2774,2780],{"type":47,"value":2739},"Every new property: ",{"type":41,"tag":141,"props":2741,"children":2743},{"className":2742},[],[2744],{"type":47,"value":1698},{"type":47,"value":266},{"type":41,"tag":141,"props":2747,"children":2749},{"className":2748},[],[2750],{"type":47,"value":2751},"[DesignerSerializationVisibility]",{"type":47,"value":2753},", or ",{"type":41,"tag":141,"props":2755,"children":2757},{"className":2756},[],[2758],{"type":47,"value":1668},{"type":47,"value":194},{"type":41,"tag":141,"props":2761,"children":2763},{"className":2762},[],[2764],{"type":47,"value":1676},{"type":47,"value":2766},"; plus ",{"type":41,"tag":141,"props":2768,"children":2770},{"className":2769},[],[2771],{"type":47,"value":2772},"[Category]",{"type":47,"value":194},{"type":41,"tag":141,"props":2775,"children":2777},{"className":2776},[],[2778],{"type":47,"value":2779},"[Description]",{"type":47,"value":533},{"type":41,"tag":72,"props":2782,"children":2783},{},[2784,2786,2791,2793,2798],{"type":47,"value":2785},"Interdependent or expensive property setters → ",{"type":41,"tag":141,"props":2787,"children":2789},{"className":2788},[],[2790],{"type":47,"value":2150},{"type":47,"value":2792}," with a ",{"type":41,"tag":141,"props":2794,"children":2796},{"className":2795},[],[2797],{"type":47,"value":2455},{"type":47,"value":2799}," guard.",{"type":41,"tag":72,"props":2801,"children":2802},{},[2803,2805,2811],{"type":47,"value":2804},"Designer SDK preview ",{"type":41,"tag":141,"props":2806,"children":2808},{"className":2807},[],[2809],{"type":47,"value":2810},"1.13.0-preview.2.24575.3",{"type":47,"value":2812}," if design-time code is involved.",{"type":41,"tag":2814,"props":2815,"children":2816},"style",{},[2817],{"type":47,"value":2818},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2820,"total":2351},[2821,2833,2839,2856,2866,2881,2898],{"slug":2822,"name":2822,"fn":2823,"description":2824,"org":2825,"tags":2826,"stars":22,"repoUrl":23,"updatedAt":2832},"converting-to-cpm","migrate .NET projects to Central Package Management","Converts .NET projects and solutions to NuGet Central Package Management (CPM) with Directory.Packages.props. Use when the user wants to centralize, convert, align, or sync NuGet package versions across multiple projects, resolve version conflicts or mismatches, or get versions consistent across a solution or repository. Also triggers when packages are out of sync or drifting across projects.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2827,2828,2829],{"name":13,"slug":14,"type":15},{"name":9,"slug":8,"type":15},{"name":2830,"slug":2831,"type":15},"Migration","migration","2026-07-18T05:14:13.971821",{"slug":4,"name":4,"fn":5,"description":6,"org":2834,"tags":2835,"stars":22,"repoUrl":23,"updatedAt":24},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2836,2837,2838],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":20,"slug":21,"type":15},{"slug":2840,"name":2840,"fn":2841,"description":2842,"org":2843,"tags":2844,"stars":22,"repoUrl":23,"updatedAt":2855},"managing-winforms-high-dpi-layout","design high-DPI responsive WinForms layouts","Implements WinForms high-DPI fluent layouts using TableLayoutPanel, FlowLayoutPanel, and DPI-aware design patterns. Use when creating responsive form layouts that must scale across different DPI settings, implementing Per Monitor V2 (PerMonitorV2) DPI awareness, working with TableLayoutPanel.RowStyles\u002FColumnStyles, using FlowLayoutPanel for dynamic layouts, replacing fixed pixel positioning with container-based layout, troubleshooting DPI scaling issues, or structuring nested layout containers. Also triggers for \"TableLayoutPanel\", \"FlowLayoutPanel\", \"high DPI WinForms\", \"PerMonitorV2\", \"DPI aware layout\", \"responsive WinForms\", \"scale UI\", \"AutoScaleMode\", and \"DPI scaling\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2845,2848,2851,2854],{"name":2846,"slug":2847,"type":15},"Design","design",{"name":2849,"slug":2850,"type":15},"Desktop","desktop",{"name":2852,"slug":2853,"type":15},"UI Components","ui-components",{"name":17,"slug":18,"type":15},"2026-07-18T05:14:12.982806",{"slug":2857,"name":2857,"fn":2858,"description":2859,"org":2860,"tags":2861,"stars":22,"repoUrl":23,"updatedAt":2865},"managing-winforms-mvvm","implement MVVM pattern in WinForms","Implements MVVM pattern in WinForms applications (.NET 8+) with ViewModels, Commands, and DataContext. Use when user explicitly requests MVVM implementation, setting up ViewModel with INotifyPropertyChanged or ObservableObject, implementing ICommand or RelayCommand, wiring Form.DataContext, binding controls to ViewModel properties, creating Commands for button clicks, or separating business logic from UI code. Also triggers for \"WinForms MVVM\", \"ViewModel in WinForms\", \"INotifyPropertyChanged\", \"DataContext binding\", \"Command pattern WinForms\", \"ObservableObject\", \"RelayCommand\", and \"testable WinForms\". Also use when fixing existing MVVM code or when guided by winforms-feature-adoption scenario. DO NOT USE FOR: automatic application during version upgrades (opt-in only).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2862,2863,2864],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":20,"slug":21,"type":15},"2026-07-18T05:14:11.951511",{"slug":2867,"name":2867,"fn":2868,"description":2869,"org":2870,"tags":2871,"stars":22,"repoUrl":23,"updatedAt":2880},"migrating-aspnet-framework-to-core","migrate ASP.NET Framework to Core","Orchestrates migration of ASP.NET Framework (System.Web) MVC and WebAPI projects to ASP.NET Core. Covers only old .NET Framework web projects — not applicable to ASP.NET Core or modern .NET web projects (those are already on the target stack). Defines the ordered phase sequence (project file, host, config, DI, controllers, middleware, auth, views, cleanup), satellite skill dispatch, and migration unit breakdown for both in-place and side-by-side modes. Use when executing a task that upgrades a project with System.Web dependencies, HttpModules, HttpHandlers, MVC controllers, WebAPI controllers, or Global.asax. Also triggers for \"migrate ASP.NET to Core\", \"upgrade MVC project\", \"convert WebAPI to ASP.NET Core\". Not applicable to class libraries unless they directly reference System.Web.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2872,2873,2876,2879],{"name":13,"slug":14,"type":15},{"name":2874,"slug":2875,"type":15},"ASP.NET Core","asp-net-core",{"name":2877,"slug":2878,"type":15},"Backend","backend",{"name":2830,"slug":2831,"type":15},"2026-07-03T16:30:55.581898",{"slug":2882,"name":2882,"fn":2883,"description":2884,"org":2885,"tags":2886,"stars":22,"repoUrl":23,"updatedAt":2897},"migrating-documentdb-to-cosmos","migrate DocumentDB to Cosmos DB","Migrates from the deprecated Microsoft.Azure.DocumentDB SDK (V2) to the modern Microsoft.Azure.Cosmos SDK (V3) for Azure Cosmos DB. Use ONLY when Microsoft.Azure.DocumentDB has been flagged as deprecated or obsolete and must be replaced — not for version-bump scenarios where the V2 SDK is still supported.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2887,2890,2893,2896],{"name":2888,"slug":2889,"type":15},"Azure","azure",{"name":2891,"slug":2892,"type":15},"Cosmos DB","cosmos-db",{"name":2894,"slug":2895,"type":15},"Database","database",{"name":2830,"slug":2831,"type":15},"2026-07-03T16:31:21.932144",{"slug":2899,"name":2899,"fn":2900,"description":2901,"org":2902,"tags":2903,"stars":22,"repoUrl":23,"updatedAt":2911},"migrating-global-asax","migrate Global.asax to ASP.NET Core middleware","Migrates Global.asax application lifecycle events to ASP.NET Core middleware, startup configuration, and Program.cs. Use when upgrading ASP.NET Framework apps containing Global.asax or Global.asax.cs files. Triggers for \"migrate Global.asax\", \"convert application events\", \"move Application_Start to Program.cs\", \"replace Global.asax with middleware\", and ASP.NET-to-Core migration involving request lifecycle, error handling, or session management.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2904,2906,2907,2908],{"name":2874,"slug":2905,"type":15},"aspnet-core",{"name":9,"slug":8,"type":15},{"name":2830,"slug":2831,"type":15},{"name":2909,"slug":2910,"type":15},"Modernization","modernization","2026-07-07T06:54:34.226435",{"items":2913,"total":3100},[2914,2936,2953,2974,2989,3006,3017,3030,3045,3060,3075,3088],{"slug":2915,"name":2915,"fn":2916,"description":2917,"org":2918,"tags":2919,"stars":2933,"repoUrl":2934,"updatedAt":2935},"rushstack-best-practices","manage Rush monorepos with best practices","Provides best practices and guidance for working with Rush monorepos. Use when the user is working in a Rush-based repository, asks about Rush commands (install, update, build, rebuild), needs help with project selection, dependency management, build caching, subspace configuration, or troubleshooting Rush-specific issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2920,2923,2926,2927,2930],{"name":2921,"slug":2922,"type":15},"Engineering","engineering",{"name":2924,"slug":2925,"type":15},"Local Development","local-development",{"name":9,"slug":8,"type":15},{"name":2928,"slug":2929,"type":15},"Project Management","project-management",{"name":2931,"slug":2932,"type":15},"Rush","rush",6484,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frushstack","2026-04-06T18:34:44.965032",{"slug":2937,"name":2937,"fn":2938,"description":2939,"org":2940,"tags":2941,"stars":2950,"repoUrl":2951,"updatedAt":2952},"azure-ai-agents-persistent-dotnet","build AI agents with Azure .NET SDK","Azure AI Agents Persistent SDK for .NET. Low-level SDK for creating and managing AI agents with threads, messages, runs, and tools. Use for agent CRUD, conversation threads, streaming responses, function calling, file search, and code interpreter. Triggers: \"PersistentAgentsClient\", \"persistent agents\", \"agent threads\", \"agent runs\", \"streaming agents\", \"function calling agents .NET\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2942,2943,2946,2947],{"name":13,"slug":14,"type":15},{"name":2944,"slug":2945,"type":15},"Agents","agents",{"name":2888,"slug":2889,"type":15},{"name":2948,"slug":2949,"type":15},"LLM","llm",2804,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fskills","2026-07-03T16:32:10.297433",{"slug":2954,"name":2954,"fn":2955,"description":2956,"org":2957,"tags":2958,"stars":2950,"repoUrl":2951,"updatedAt":2973},"azure-ai-anomalydetector-java","build anomaly detection applications with Java","Build anomaly detection applications with Azure AI Anomaly Detector SDK for Java. Use when implementing univariate\u002Fmultivariate anomaly detection, time-series analysis, or AI-powered monitoring.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2959,2962,2963,2966,2969,2970],{"name":2960,"slug":2961,"type":15},"Analytics","analytics",{"name":2888,"slug":2889,"type":15},{"name":2964,"slug":2965,"type":15},"Data Analysis","data-analysis",{"name":2967,"slug":2968,"type":15},"Java","java",{"name":9,"slug":8,"type":15},{"name":2971,"slug":2972,"type":15},"Monitoring","monitoring","2026-05-13T06:14:16.261754",{"slug":2975,"name":2975,"fn":2976,"description":2977,"org":2978,"tags":2979,"stars":2950,"repoUrl":2951,"updatedAt":2988},"azure-ai-contentsafety-java","build content moderation applications with Azure AI","Build content moderation applications with Azure AI Content Safety SDK for Java. Use when implementing text\u002Fimage analysis, blocklist management, or harm detection for hate, violence, sexual content, and self-harm.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2980,2983,2984,2985],{"name":2981,"slug":2982,"type":15},"AI Infrastructure","ai-infrastructure",{"name":2888,"slug":2889,"type":15},{"name":2967,"slug":2968,"type":15},{"name":2986,"slug":2987,"type":15},"Security","security","2026-07-07T06:53:31.293235",{"slug":2990,"name":2990,"fn":2991,"description":2992,"org":2993,"tags":2994,"stars":2950,"repoUrl":2951,"updatedAt":3005},"azure-ai-contentsafety-py","detect harmful content with Azure AI Content Safety","Azure AI Content Safety SDK for Python. Use for detecting harmful content in text and images with multi-severity classification.\nTriggers: \"azure-ai-contentsafety\", \"ContentSafetyClient\", \"content moderation\", \"harmful content\", \"text analysis\", \"image analysis\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2995,2996,2999,3000,3001,3004],{"name":2888,"slug":2889,"type":15},{"name":2997,"slug":2998,"type":15},"Compliance","compliance",{"name":2948,"slug":2949,"type":15},{"name":9,"slug":8,"type":15},{"name":3002,"slug":3003,"type":15},"Python","python",{"name":2986,"slug":2987,"type":15},"2026-07-18T05:14:23.017504",{"slug":3007,"name":3007,"fn":3008,"description":3009,"org":3010,"tags":3011,"stars":2950,"repoUrl":2951,"updatedAt":3016},"azure-ai-language-conversations-py","implement conversational language understanding with Python","Implement Conversational Language Understanding (CLU) using the azure-ai-language-conversations Python SDK. Use when working with ConversationAnalysisClient to analyze conversation intent and entities, building NLP features, or integrating language understanding into applications.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3012,3013,3014,3015],{"name":2960,"slug":2961,"type":15},{"name":2888,"slug":2889,"type":15},{"name":2948,"slug":2949,"type":15},{"name":3002,"slug":3003,"type":15},"2026-07-31T05:54:29.068751",{"slug":3018,"name":3018,"fn":3019,"description":3020,"org":3021,"tags":3022,"stars":2950,"repoUrl":2951,"updatedAt":3029},"azure-ai-translation-text-py","translate text using Azure AI services","Azure AI Text Translation SDK for real-time text translation, transliteration, language detection, and dictionary lookup. Use for translating text content in applications.\nTriggers: \"text translation\", \"translator\", \"translate text\", \"transliterate\", \"TextTranslationClient\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3023,3026,3027,3028],{"name":3024,"slug":3025,"type":15},"API Development","api-development",{"name":2888,"slug":2889,"type":15},{"name":9,"slug":8,"type":15},{"name":3002,"slug":3003,"type":15},"2026-07-18T05:14:16.988376",{"slug":3031,"name":3031,"fn":3032,"description":3033,"org":3034,"tags":3035,"stars":2950,"repoUrl":2951,"updatedAt":3044},"azure-ai-vision-imageanalysis-py","analyze images with Azure AI Vision","Azure AI Vision Image Analysis SDK for captions, tags, objects, OCR, people detection, and smart cropping. Use for computer vision and image understanding tasks.\nTriggers: \"image analysis\", \"computer vision\", \"OCR\", \"object detection\", \"ImageAnalysisClient\", \"image caption\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3036,3037,3040,3043],{"name":2888,"slug":2889,"type":15},{"name":3038,"slug":3039,"type":15},"Computer Vision","computer-vision",{"name":3041,"slug":3042,"type":15},"Images","images",{"name":3002,"slug":3003,"type":15},"2026-07-18T05:14:18.007737",{"slug":3046,"name":3046,"fn":3047,"description":3048,"org":3049,"tags":3050,"stars":2950,"repoUrl":2951,"updatedAt":3059},"azure-appconfiguration-java","manage configuration with Azure App Configuration","Azure App Configuration SDK for Java. Centralized application configuration management with key-value settings, feature flags, and snapshots.\nTriggers: \"ConfigurationClient java\", \"app configuration java\", \"feature flag java\", \"configuration setting java\", \"azure config java\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3051,3052,3055,3058],{"name":2888,"slug":2889,"type":15},{"name":3053,"slug":3054,"type":15},"Configuration","configuration",{"name":3056,"slug":3057,"type":15},"Feature Flags","feature-flags",{"name":2967,"slug":2968,"type":15},"2026-07-03T16:32:01.278468",{"slug":3061,"name":3061,"fn":3062,"description":3063,"org":3064,"tags":3065,"stars":2950,"repoUrl":2951,"updatedAt":3074},"azure-cosmos-rust","build applications with Azure Cosmos DB","Azure Cosmos DB library for Rust (NoSQL API). Document CRUD, containers, and globally distributed data.\nTriggers: \"cosmos db rust\", \"CosmosClient rust\", \"document crud rust\", \"NoSQL rust\", \"partition key rust\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3066,3067,3068,3071],{"name":2891,"slug":2892,"type":15},{"name":2894,"slug":2895,"type":15},{"name":3069,"slug":3070,"type":15},"NoSQL","nosql",{"name":3072,"slug":3073,"type":15},"Rust","rust","2026-07-31T05:54:27.021432",{"slug":3076,"name":3076,"fn":3062,"description":3077,"org":3078,"tags":3079,"stars":2950,"repoUrl":2951,"updatedAt":3087},"azure-cosmos-ts","Azure Cosmos DB JavaScript\u002FTypeScript SDK (@azure\u002Fcosmos) for data plane operations. Use for CRUD operations on documents, queries, bulk operations, and container management. Triggers: \"Cosmos DB\", \"@azure\u002Fcosmos\", \"CosmosClient\", \"document CRUD\", \"NoSQL queries\", \"bulk operations\", \"partition key\", \"container.items\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3080,3081,3082,3083,3084],{"name":2891,"slug":2892,"type":15},{"name":2894,"slug":2895,"type":15},{"name":9,"slug":8,"type":15},{"name":3069,"slug":3070,"type":15},{"name":3085,"slug":3086,"type":15},"TypeScript","typescript","2026-07-03T16:31:19.368382",{"slug":3089,"name":3089,"fn":3090,"description":3091,"org":3092,"tags":3093,"stars":2950,"repoUrl":2951,"updatedAt":3099},"azure-data-tables-java","build table storage applications with Java","Build table storage applications with Azure Tables SDK for Java. Use when working with Azure Table Storage or Cosmos DB Table API for NoSQL key-value data, schemaless storage, or structured data at scale.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3094,3095,3096,3097,3098],{"name":2888,"slug":2889,"type":15},{"name":2891,"slug":2892,"type":15},{"name":2894,"slug":2895,"type":15},{"name":2967,"slug":2968,"type":15},{"name":3069,"slug":3070,"type":15},"2026-05-13T06:14:17.582229",267]