Skip to content

Commit 8554492

Browse files
.NET 11: integrate application, rendering, and visual styles APIs (dotnet#14809)
* Add feature promp, * Factor system text scale lookup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add system text size APIs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add system text size tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add WinRT UISettings accent-color interop to Core Hand-author the IUISettings3 / UIColor / UIColorType WinRT ABI types and generate the RoActivateInstance / WindowsCreateString / WindowsDeleteString / IInspectable / HSTRING Win32 bindings via CsWin32. The WinRT ABI types are excluded from the .NET Framework build, which does not consume them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Application.GetWindowsAccentColor() Expose the user's current Windows accent color by activating the Windows.UI.ViewManagement.UISettings runtime component and reading UIColorType.Accent. When no accent color is set, Windows returns an OS-defined default, so the method always yields a usable color. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify system text size notifications Use event subscriptions as the opt-in for text-size notifications and remove the redundant awareness API surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40d0f0f7-a584-4167-9187-9d529b7c70f8 * Fix system text size analyzer diagnostics Wrap the Form event remark in a paragraph and remove the redundant nullable handler initialization reported by the Arcade analyzers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40d0f0f7-a584-4167-9187-9d529b7c70f8 * Add system visual settings snapshot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Clean up visual settings tracker formatting Preserve the Integration-3 coding-standard cleanup with the Application visual-settings feature that owns the tracker. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Rename SystemVisualSettingsCategories.Animations to ClientAreaAnimations API Review board final naming: the animation category flag is renamed from Animations to ClientAreaAnimations to match its underlying SystemVisualSettings.ClientAreaAnimationEnabled source. Value (1 << 3) unchanged. Updates the tracker, PublicAPI.Unshipped.txt, and tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Guard queued settings refresh before handle creation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Add TreeView.NodeLeading API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add TreeView.NodeLeading tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cover NodeLeading DPI resynchronization Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 * Add the prompts for the new Suspend-Positioning-Painting-Form-Apearance API. * Add flicker-free mutation API proposal prompt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add flicker-free UI mutation APIs Implements suspend painting and relocation scopes, deferred child positioning, and form appearance mode infrastructure for .NET 11. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add tests for flicker-free mutation APIs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove DeferLocationChange; make suspend-mutation hooks explicit-interface Splits DeferLocationChange out of this branch entirely (postponed pending an anchor-layout-engine integration fix; tracked separately in KlausLoeffelmann/winforms#12) and reworks ISupportSuspendPainting / ISupportSuspendRelocation on Control to match the final API shape agreed in dotnet/winforms#14585: - Control implements ISupportSuspendPainting/ISupportSuspendRelocation via explicit interface implementation instead of public virtual methods, so the manual Begin/End pair does not become the primary IntelliSense surface on every Control-derived type. Protected virtual BeginSuspendPaintingCore() / EndSuspendPaintingCore() / BeginSuspendRelocationCore() / EndSuspendRelocationCore() are the new override points. - ListView, ListBox, ComboBox, TreeView, RichTextBox override the ...Core() hooks instead of the old public virtual methods, still routing through their existing BeginUpdate/EndUpdate. - SuspendPaintingScope and SuspendRelocationScope change from readonly ref struct to sealed class : IDisposable, so the scope can span an await in an asynchronous UI event handler (a ref struct cannot be hoisted into an async state machine - this was the flagship usage scenario in the original API proposal, and it did not compile against the ref struct version). Dispose is idempotent. - Deletes DeferLocationChangeScope.cs and the Control.DeferLocationChange overloads entirely. - Updates/removes tests accordingly; updates PublicAPI.Unshipped.txt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rename FormAppearanceMode to FormRevealMode with Inherit ambient sentinel Matches the final API shape agreed in dotnet/winforms#14585: - FormAppearanceMode -> FormRevealMode, adding Inherit = -1 as the ambient sentinel (Classic stays the CLR default value 0, matching the RightToLeft.Inherit / VisualStylesMode.Inherit precedent for ambient enums - the sentinel is a distinct value, not the zero value, so default(FormRevealMode) stays conservative). - Form.FormRevealMode is now a real public virtual, PropertyStore-backed, [AmbientValue(Inherit)] property (previously there was no per-Form property at all - only the flat, process-wide Application.FormAppearanceMode existed). This lets a form such as a splash screen opt itself out of deferred reveal without touching the process-wide default. Resolution is flat (Form only, no Control-parent-chain): DWM cloaking only ever applies to top-level, non-MDI-child windows, so there is no hierarchy to walk, unlike VisualStylesMode's genuine control-nesting cascade. - Application.FormAppearanceMode / SetFormAppearanceMode are replaced by three members: DefaultFormRevealMode (get; may return the unresolved Inherit sentinel, mirroring ColorMode returning the unresolved System value), SetDefaultFormRevealMode (freely reassignable, unlike the write-once SetDefaultVisualStylesMode - the effective default is derived in part from ColorMode/IsDarkModeEnabled, which are themselves mutable for the life of the process), and IsFormRevealDeferred (bool; the fully resolved answer: Deferred, or Inherit + IsDarkModeEnabled). This also fixes a compatibility problem in the original design: the old default was unconditionally Deferred whenever SetFormAppearanceMode was never called, an opt-out behavior change for every existing app; tying the Inherit resolution to dark mode means an app that never touches SystemColorMode sees no behavior change, while the scenario the feature exists for (dark-mode startup flash) is fixed by default. - ShouldUseDeferredAppearanceCloak now reads the resolved Form.FormRevealMode instead of the old flat Application-only check, so a per-Form override is actually honored. - Adds SR.resx/xlf entries for the new property's designer description. - Updates/adds tests; updates PublicAPI.Unshipped.txt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Wire FormRevealMode into the VB Application Framework Adds Microsoft.VisualBasic.ApplicationServices.ApplyApplicationDefaultsEventArgs.FormRevealMode, following the exact same pattern already established for ColorMode and HighDpiMode in that class, per dotnet/winforms#14585's API Proposal. WindowsFormsApplicationBase now carries a _formRevealMode shadow field (defaulting to FormRevealMode.Classic, matching the existing conservative default for _colorMode) and a protected FormRevealMode property, feeds it into the ApplyApplicationDefaultsEventArgs constructor alongside MinimumSplashScreenDisplayTime/HighDpiMode/ColorMode, reads back whatever the ApplyApplicationDefaults event handler set, and calls Application.SetDefaultFormRevealMode(_formRevealMode) at the end of OnInitialize alongside the existing Application.SetColorMode(_colorMode) call. This completes work anticipated but never finished in an earlier .NET 9 Visual Styles attempt at this same VB Application Framework extension point (OnInitialize already carried a comment claiming "We feed the defaults for HighDpiMode, ColorMode, VisualStylesMode to the EventArgs", but only HighDpiMode/ColorMode were ever actually wired up). Updates PublicAPI.Unshipped.txt for Microsoft.VisualBasic.Forms. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix FormRevealMode public API tracking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 * Preserve painting suspension across handles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 * Add layout-aware painting suspension Remove the risky relocation API and add controlled layout traversal to painting scopes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9c3dc32b-7202-48c4-b0c7-f40a0a681ee2 * Fix FormRevealMode.Deferred cloak never engaging ShouldUseDeferredAppearanceCloak() gated the DWM cloak on Visible == true, but it is only evaluated from OnHandleCreated, where a top-level form's window is still hidden (WS_VISIBLE is cleared from the create params and the show is deferred). The Visible state bit is not set until WM_SHOWWINDOW is processed, so the guard was always false, the cloak never engaged, and the window was shown uncloaked - still producing the default-background flash the mode is meant to prevent. Remove the Visible term so the already-hidden window is cloaked at handle creation. This covers Show, ShowDialog (which creates the handle via CreateControl before showing) and handle recreation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 78934db49c7c1fac3da0c366c2a27a9e323ba2cd) * Apply API Review tweaks to flicker-free mutation and FormRevealMode APIs Flicker-free UI mutation API: - Rename LayoutSuspendTraversal members for clarity and redefine semantics: None -> TargetOnly (0), TopLevelOnly -> TargetAndChildren (1, new: target plus immediate children), Traverse -> TargetAndDescendants (2). The painting-only (no layout suspension) case is now served solely by the parameterless SuspendPainting overload. - Make SuspendPaintingScope internal; the three ControlMutationExtensions .SuspendPainting overloads now return IDisposable. The await-safe / idempotent guidance moves to the public extension-method docs so it stays discoverable. - Document that Control implements ISupportSuspendPainting explicitly (callers use the IDisposable scope; overriders use Begin/EndSuspendPaintingCore). FormRevealMode: - Add the FormRevealModeChanged event and protected virtual OnFormRevealModeChanged, raised from the setter when the effective value changes. Updates PublicAPI.Unshipped.txt, SR.resx, and ControlTests.Methods.cs (including a new TargetAndChildren test). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Sync XLF localization stubs for FormOnFormRevealModeChangedDescr Generated by the build after adding the FormRevealModeChanged event description to SR.resx. Keeps the localized .xlf files in sync with the neutral resources. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Refine LayoutSuspendTraversal: restore None, drop TargetAndChildren Per follow-up review: the parameterless SuspendPainting overload already covers the painting-only case, but keeping an explicit None = 0 restores the intuitive default (no layout suspension) and avoids default(enum) silently suspending. TargetAndChildren is removed because the distinction from TargetOnly was subtle and confusing (a container's SuspendLayout already holds its children's layout). Final enum: None = 0, TargetOnly = 1, TargetAndDescendants = 2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Fix deferred FormRevealMode residual flash by revealing after full first paint Deferred reveal cloaked the form at OnHandleCreated and uncloaked on the form's own first WM_PAINT. That paint fires before the child controls - separate child windows - paint their first frame, so the window was revealed mid-paint and the tail of the startup flash (controls popping in) was still visible. Reveal only after the whole control tree has painted its first frame: - Add Form.RevealDeferredAppearance(): force a synchronous full-tree paint of the still-cloaked window (RedrawWindow RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN| RDW_UPDATENOW), then uncloak, so the finished frame appears at once. It is a no-op once revealed / never cloaked, and guarded against re-entrancy since RDW_UPDATENOW dispatches WM_PAINT synchronously. - Trigger it from OnShown (CallShownEvent) as the primary, guaranteed one-shot point that runs before the first natural WM_PAINT, and keep the WM_PAINT hook as an idempotent fallback so the window can never be revealed mid-paint or stay stuck cloaked. Adds a safety-invariant test: a shown Deferred form must not remain cloaked. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Fix FormRevealMode doc cref namespace qualification Several XML doc comments referenced <see cref="Forms.FormRevealMode"/>, an inconsistent partial-namespace qualification for the FormRevealMode enum. Use the unqualified enum name FormRevealMode (as elsewhere in the file, e.g. FormRevealMode.Inherit) so the cref resolves cleanly and matches the surrounding "a FormRevealMode value" wording. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Update agent skills: build.cmd build tenet, PublicAPI override tracking, and test cancellation/nullable guidance - building-code: add a top-level TENET to build the solution only with build.cmd (CI parity for PublicAPI/analyzer enforcement and -warnAsError); a plain dotnet build is inner-loop only. - new-control-api: new public/protected overrides must be tracked in PublicAPI.Unshipped.txt with the override prefix; note CS0114 (new keyword) and CS1574 (no cref to cross-assembly internal types). - control-api-tests: async tests must pass CancellationToken (TestContext.Current.CancellationToken, CA2016/xUnit1051) and respect the #nullable context (CS8632). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Visual Styles (.NET 11): VisualStylesMode, animation timer, modern Button and CheckBox toggle renderers Introduces the (non-experimental) Visual Styles versioning API and the first modern renderers gated behind it: - VisualStylesMode enum (Classic/Disabled/Net11/Latest); ambient Control.VisualStylesMode (+event/On-methods); Application.DefaultVisualStylesMode/SetDefaultVisualStylesMode; Appearance.ToggleSwitch; VB framework APIs. - HighPrecisionTimer (internal, Primitives) as the animation frame trigger, with tests. - AnimationManager/AnimatedControlRenderer driven by HighPrecisionTimer. - Conservative dark-mode Standard button (owner-drawn, reachable) + modern WinUI-style Button renderer. - CheckBox Appearance.ToggleSwitch modern toggle switch (animated, flicker-free). - WinformsControlsTest VisualStylesButtons exploratory harness; unit tests. Verified CI-clean with build.cmd: System.Windows.Forms, Microsoft.VisualBasic.Forms and Primitives build with no analyzer/PublicAPI/style errors (the only remaining failure is the pre-existing BuildAssist/AxHosts step, which is an environment limitation unrelated to these changes). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix minor test issue. * Patch XML docs for TextBoxBase' Padding property. * Add work order for TextBoxBase NC painting port * Add solution folders "Application" and "net11-VisualStylesMode" to Winforms.sln and include a detailed Markdown work order for porting non-client painting and VisualStylesMode chrome to VisualStylesNet11. * Update solution structure to organize these items for engineering reference. * Port TextBoxBase NC-painting + VisualStylesMode chrome onto VisualStylesNet11 Bring the non-client (NC) painting feature for TextBoxBase/TextBox from the pinned SHA cf32e9c4 onto the modern VisualStylesNet11 layout, with the DECIDED design changes and the Prompt-2 MUST-FIX items applied. TextBoxBase.cs: * Add VisualStyles border-padding consts + BorderThickness and the _triggerNewClientSizeRequest latch (reset in CreateHandle). * Split PreferredHeight into a VisualStylesMode switch over PreferredHeightCore (modern) and PreferredHeightClassic (Everett-compatible). Dropped the original [Experimental]/WFO5000 gating - VisualStyles is not experimental on this branch. * Add GetVisualStylesPadding / virtual GetScrollBarPadding (DPI-scaled). * Add the VisualStylesMode >= Net11 branch to GetPreferredSizeCore. * Add WmNcPaint / OnNcPaint / InitializeClientArea / WmNcCalcSize and the WM_NCCALCSIZE / WM_NCPAINT WndProc cases; wire InitializeClientArea into InitializeDCForWmCtlColor. * Add NC-frame invalidation to OnGotFocus / OnLostFocus / OnSizeChanged (OnLostFocus now correctly guarded by VisualStylesMode, fixing the original asymmetry). DECIDED design (work-order steps 6-8): * Use the shared BufferedGraphics buffer (BufferedGraphicsManager.Current) instead of the per-instance NonClientBitmapCache; buffer.Render() blits to the window DC. * Use the shipped Graphics.FillRoundedRectangle / DrawRoundedRectangle methods. * Never-invert clamp in WmNcCalcSize (no MinimumSize); paint-time chrome degradation in OnNcPaint below the viable rounded-chrome height. * Fixed the WmNcPaint double-dispose. MUST-FIX: * DPI-scale the corner radius and border thickness (and the degradation threshold) via LogicalToDeviceUnits. TextBox.cs: * Guard the classic PRF_NONCLIENT Fixed3D border draw so it does not double-draw over the modern chrome when VisualStylesMode >= Net11. NativeMethods.txt: * Generate GetWindowDC and NCCALCSIZE_PARAMS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten OCE handling in HighPrecisionTimer callback dispatch Previously InvokeCallbackAsync used 'catch (Exception ex) when (ex is not OperationCanceledException)', which let an OperationCanceledException escape the handler entirely. Because the callback runs as a discarded fire-and-forget task (SyncContext.Post of '_ = InvokeCallbackAsync(...)'), the escaping OCE faulted that task into an unobserved task exception that only surfaced via TaskScheduler.UnobservedTaskException on GC. Catch the OCE explicitly and ignore it when our cancellation token is signalled (mirroring the TimerLoopAsync convention), so cancellation during timer shutdown is a clean no-op. Genuine, non-cancellation exceptions still route to Debug.Fail. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add VisualStylesMode.Inherit ambient sentinel for designer serialization VisualStylesMode and DataContext are ambient via property-store absence, which is sufficient at runtime and for the normal serialization path. But a 'truly ambient' property the designer can reset also needs a writable 'inherit' token: the CodeDOM serializer (PropertyMemberCodeDomSerializer) substitutes an [AmbientValue] when it is forced to emit an otherwise-ambient property (inherited/'difference' forms, member relationships, absolute serialization). Without it the resolved concrete value is baked in, breaking re-inheritance in those designer scenarios. VisualStylesMode had no inherit sentinel, so [AmbientValue] had no correct value to use. Add one, mirroring RightToLeft.Inherit: * Add VisualStylesMode.Inherit (= -1). It is an assignable sentinel; the resolved value is never Inherit (the getter resolves a stored/assigned Inherit to the parent or Application.DefaultVisualStylesMode), so the '>= Net11' gating elsewhere is unaffected. * Annotate Control.VisualStylesMode with [AmbientValue(VisualStylesMode.Inherit)] and make the setter treat Inherit (and 'equals parent') as 'clear the local override' so it re-inherits; raise the change event only when the resolved value changes. * Reject VisualStylesMode.Inherit in Application.SetDefaultVisualStylesMode (the app root has no parent to inherit from); also validate undefined values there. * DataContext deliberately keeps NO [AmbientValue]: its setter stores an explicit null rather than clearing the override, so null would be a leaky 'inherit' sentinel. Added a maintainer comment explaining why. Update PublicAPI.Unshipped.txt, SR + xlf, and the VisualStylesMode unit tests (the old '-1 is invalid' case is now Inherit; add re-inherit, never-returns-Inherit, and SetDefaultVisualStylesMode(Inherit) throws coverage). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add VisualStylesMode.LatestPreview support Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Gate TextBoxBase padding to modern visual styles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Wire VisualStylesMode through VB application defaults Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix modern Visual Styles NC-paint erasing TextBox client area; refactor TextBoxBase WM_NCPAINT now passes base.WndProc a client-excluding update region (screen coordinates) so the default themed non-client paint no longer erases the edit client area (e.g. on hover) for scrollbar-bearing TextBox/RichTextBox. Also: fix Release-only CS8175 by capturing the cached Pen (not the ref-struct scope) in the OnNcPaint focus-line local functions; extract the RichEdit-specific ScrollToCaret logic into a RichTextBox override of a new private protected virtual ScrollToCaretCore; and documentation/comment cleanups (GetVisualStylesPadding, GetPreferredSizeCore, WindowText, PaddingChanged) plus Everett capitalization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Tighten modern Standard button body/focus-ring spacing Shrink the gap between the rounded button body and the outer focus ring and grow the body to reclaim that space. When the focus ring is not drawn, the body now expands to fill the ring+gap band via a focus-aware GetContentPadding hook, so unfocused buttons feel less cramped without changing the control's Padding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Replace Popup button style with animated concave key-cap renderer Port the prototype material key-cap renderer into System.Windows.Forms.Rendering.Button (renamed to Popup/FlatStyle conventions, no MaterialKey naming). Button owner-paints FlatStyle.Popup under modern visual styles or dark mode via a timer-driven AnimatedPopupButtonRenderer that interpolates hover/press channels through the shared AnimationManager, mirroring the CheckBox toggle switch. Border width/color are read from FlatButtonAppearance. The old PopupButtonDarkModeRenderer is removed; the dark-mode adapter keeps the modern renderer for Popup layout only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use modern owner-drawn renderers for Appearance.Button CheckBox/RadioButton Route the Appearance.Button rendering of CheckBox and RadioButton through DarkModeAdapterFactory so it reuses the modern ButtonDarkModeAdapter/renderers under dark mode or modern visual styles, matching modern push buttons (including checked-as-pressed state). Classic mode is unchanged. The concrete-type ButtonAdapter casts are dropped so the delegated adapter can be the shared ButtonDarkModeAdapter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Position modern toggle switch by CheckAlign instead of TextAlign The Appearance.ToggleSwitch renderer placed the switch based on TextAlign, so the default (MiddleLeft) drew the switch on the right. Drive placement from CheckAlign instead: left/center-aligned values (including the MiddleLeft default) put the switch on the left with the caption on the right, and right-aligned values put it on the right. Vertical centering is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add EffectiveVisualStylesMode for High Contrast support Introduce EffectiveVisualStylesMode to clamp visual styles to Classic when Windows High Contrast is active, ensuring consistent rendering and accessibility. Update all controls to use this property for rendering and CreateParams decisions. * Override Form.OnSystemColorsChanged to handle High Contrast transitions by recreating handles as needed. Remove VisualStylesMode.LatestPreview and update related logic. * Expose EffectiveVisualStylesMode to owner-drawn button adapters for correct renderer selection. * Fix compile break from VisualStylesMode.LatestPreview removal Rewrite the write-once application default test to no longer reference the removed VisualStylesMode.LatestPreview member. The test now uses Net11 as the established (write-twice-with-same-value) mode and Latest as the differing value that must throw. Also drop stale LatestPreview mentions from the validation comments in Application.SetDefaultVisualStylesMode and Control.VisualStylesMode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Make Control.VisualStylesMode virtual Align VisualStylesMode with the other ambient properties (BackColor, Cursor, Font, ForeColor, RightToLeft), which are all public virtual. Making it virtual allows derived controls to transform the ambient value that children observe through ParentInternal.VisualStylesMode. The property is still unshipped, so this only updates the PublicAPI.Unshipped.txt entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Pin PropertyGrid hosted controls to classic visual styles Override the now-virtual Control.VisualStylesMode in PropertyGrid to always return VisualStylesMode.Classic. The editing controls hosted inside the grid read the ambient VisualStylesMode from their parent chain; because the property is virtual, they resolve to Classic and never switch to a modern renderer whose frame/glyph metrics would not line up with the grid's fixed layout. The setter stores the requested value in a backing field for potential future use but currently has no effect, so setting Net11/Latest is a genuine no-op. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Honor Padding in RichTextBox under modern visual styles RichEdit (MSFTEDIT) does not send the WM_CTLCOLOR messages a plain EDIT control uses to lazily trigger the modern Visual Styles client-area carve, so the carve never ran and Padding had no effect. RichEdit also reserves its own border and scrollbar space during WM_NCCALCSIZE, so the managed carve must be applied on top of the native result rather than the raw proposed window rectangle. - TextBoxBase: extract the carve trigger into RecalculateVisualStylesClientArea so it can be re-provoked, add the ReservesNativeNonClientArea hook so WmNcCalcSize runs the default handler first for such controls, and re-provoke the carve from OnPaddingChanged so runtime Padding changes apply. - RichTextBox: opt into ReservesNativeNonClientArea, return an empty GetScrollBarPadding (RichEdit already reserves the scrollbars), and trigger the carve explicitly in OnHandleCreated since WM_CTLCOLOR never arrives. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Add side-by-side up/down buttons for modern VisualStylesMode (A11y) When a modern VisualStylesMode (Net11 or above) is in effect, lay out the UpDownBase increment/decrement buttons side by side instead of stacked, so each button gets a larger, more accessible click target. The decrement (down) button sits on the leading edge and the increment (up) button on the trailing edge, mirrored under right-to-left. - UpDownBase: add internal UseSideBySideButtons (gated on EffectiveVisualStylesMode >= Net11); widen the button band to 2x in PositionControls when active. - UpDownButtons: centralize hit-testing in GetButtonRectangle(ButtonID) (stacked = top/bottom half, side-by-side = leading/trailing half, RTL aware); route BeginButtonPress, OnMouseMove and accessibility bounds through it. Render the modern layout with DrawModernControlButton (light + dark) and add GetButtonState mapping enabled/pushed/hot state. - DirectionButtonAccessibleObject: derive Bounds from the shared GetButtonRectangle (client coords) and map via owner.RectangleToScreen. Classic (stacked) layout and rendering are unchanged. NumericUpDown and DomainUpDown inherit the new behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Draw a unified modern frame around UpDownBase in modern VisualStylesMode Under a modern VisualStylesMode (Net11 or above) the up/down control now draws a single modern frame (the same rounded Fixed3D / flat FixedSingle chrome a stand-alone modern TextBox paints) around the whole control - both the edit and the side-by-side buttons - instead of the legacy themed single-textbox border that only wrapped the edit. - Add modern chrome geometry constants mirrored from TextBoxBase and a ModernBorderPadding helper (device-unit inset per BorderStyle). - PositionControls: split the modern layout into PositionControlsModern, which insets the edit and the (2x wide) button band by ModernBorderPadding so they sit inside the frame and clear the rounded corners; honors UpDownAlign/RTL. The classic layout is restored to its original, unchanged form. - OnPaint: in modern mode draw the frame via DrawModernBorder (corners filled with the parent back color so the rounded frame blends), skipping the themed/classic border path. - Add UpDownBaseTests covering the modern side-by-side layout geometry and that the modern paint path renders (DrawToBitmap) without throwing. Classic (non-modern) layout, rendering, and all existing UpDown tests are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 * Fix popup button release build diagnostics Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 * Harden modern visual styles behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 * Restore modern Visual Styles renderer follow-ups Reconcile the recovered button and glyph renderer work with the newer Popup and High Contrast implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8c96a2a1-9a56-4ebe-a0d4-08297832eb45 * Add LightCoral TextBox NC-paint diagnostic Tint only the clipped offscreen parent-background fill so client-area leakage during BufferedGraphics.Render is immediately visible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8c96a2a1-9a56-4ebe-a0d4-08297832eb45 * Add system text size APIs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Application.GetWindowsAccentColor() Expose the user's current Windows accent color by activating the Windows.UI.ViewManagement.UISettings runtime component and reading UIColorType.Accent. When no accent color is set, Windows returns an OS-defined default, so the method always yields a usable color. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address VisualStyles rendering follow-ups Fix non-client TextBox painting, modern button state rendering, shared Popup behavior, and font-scaled CheckBox/RadioButton toggle switches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a909fa48-8991-4d3a-8b90-617a4c026200 * Fix API tracking after dependency merge Keep the branch 01 and branch 05 API declarations as a unique union after applying the integration-tested VisualStyles patch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a909fa48-8991-4d3a-8b90-617a4c026200 * Refine modern VisualStyles rendering and layout Paint rounded cutouts from the real parent surface, refresh live visual-style changes, correct TextBox and UpDown geometry, normalize rounded paths, and improve Popup sizing and motion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: a909fa48-8991-4d3a-8b90-617a4c026200 * Adjust the default Paddings for modern VisualStyles. * Add a bit of formatting/refactoring while reviewing. * Refine modern Visual Styles chrome geometry Paint parent content beneath antialiased chrome, reduce TextBox and UpDown sizing, and cover native border suppression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 225d4d4c-7dd7-46f1-9406-b30ff07bd8b5 * Improve modern button rendering, layout, and contrast - Refactored and enhanced modern button rendering for .NET 11+ visual styles, including FlatStyle.Standard, FlatStyle.Flat, and FlatStyle.Popup. - Improved image and text layout accuracy in ButtonBaseAdapter and ButtonDarkModeAdapter, with new properties for word wrapping, image clipping, and preferred size insets. - Modern renderers now select automatic foreground colors to ensure WCAG-compliant contrast, adding outlines if needed. - Popup button palette logic tracks bowl extremes for better contrast. - ButtonBase and CheckBox reset animators on system color changes. - Preferred size calculations now use renderer metrics. - Consolidated painting logic in ButtonDarkModeAdapter. - Added methods for content bounds and chrome size in PopupButtonKeyCapRenderer. - Expanded tests for layout, preferred size, color contrast, and system color changes. - Updated internal APIs and test helpers to support these improvements. * Modernize CheckBox/Radio/ToggleSwitch visuals & animation - Use Windows accent color for CheckBox/RadioButton glyphs by default, with high contrast support and cache invalidation on system color changes. - Animate hover/focus states independently for CheckBox, RadioButton, and ToggleSwitch; add new animation channels and blending logic. - ToggleSwitch animates thumb growth on hover, uses accent color for "on" state, and improves DPI/font scaling geometry. - FlatButtonAppearance returns automatic state colors only for non-Popup styles; Popup respects explicit values. - Update TextBoxBase geometry constants (e.g., corner radius to 15), use accent color for focus unless in high contrast. - Add and update tests for accent color, animation, geometry, and accessibility. - Refactor and clean up code, adding helpers for color blending, geometry, and animation state management. * Preserve visible TextBox scrollbars Exclude live native scrollbar rectangles from modern non-client chrome blits. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9c3dc32b-7202-48c4-b0c7-f40a0a681ee2 * Refine modern text input chrome Clear the residual native edit edge, animate the clipped rounded focus indicator, and expose padding consistently on up-down controls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 33fa13dc-4960-4c84-a4fb-d1ab91741b73 * Rework high precision animation timing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Add visual styles change impact dispatch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Remove copied application APIs from visual styles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Restore Classic dark button rendering Keep the existing flat dark-mode renderer for Standard buttons in Classic mode. Net11 continues to use the modern renderer without changing legacy dark-mode geometry or separation. Fixes dotnet/winforms#14764 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Paint modern glyph controls over container backgrounds Use ParentBackgroundRenderer for modern CheckBox and RadioButton surfaces so themed and transparent containers, including TabPage, are painted instead of being cleared to an ambient color value. Fixes dotnet/winforms#14759 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Improve disabled text in modern renderers Render disabled captions without legacy relief and derive a muted color that keeps at least 3:1 contrast against the actual surface. Share the policy across modern buttons, glyph controls, toggle switches, and popup key caps while retaining GrayText as the High Contrast fallback. Fixes dotnet/winforms#14760 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Clarify ToggleSwitch visual styles behavior Document that ToggleSwitch has no effect in Classic or Disabled mode and that later visual-style versions remain control- and state-specific opt-in boundaries. Addresses dotnet/winforms#14758 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Render BackgroundImage in modern button paths Separate background and foreground image painting so modern Button, CheckBox, RadioButton, and popup renderers can preserve the correct z-order. BackgroundImageLayout and RTL positioning now flow through ControlPaint in light and dark Net11 rendering while High Contrast continues to suppress decorative images. Fixes dotnet/winforms#14753 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Keep modern Popup rendering out of Classic mode Gate the animated key-cap on the effective Net11 visual style and restore a dedicated dark Popup renderer for Classic and High Contrast fallback paths. Classic popup sizing now uses the legacy adapter metrics again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Harden modern renderer surface handling Apply disabled-text contrast to explicit foreground colors, paint rounded Classic popup corners over the real parent surface, and clip BackgroundImage content inside popup chrome and renderer content bounds. Follow-up for dotnet/winforms#14753 and dotnet/winforms#14760 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 * Add consolidated VisualStyles work order Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Share modern control chrome metrics Move modern TextBox and UpDown chrome constants into a shared internal source so subsequent renderers use one DPI-independent metric family. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Modernize GroupBox FlatStyle rendering Add mode-gated card, outline, and header-band renderers with shared layout metrics, cached scaled captions, text-scale relayout, and effective-mode UIA heading semantics. Keep FlatStyle.System native. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Modernize ComboBox FlatStyle rendering Route Net11 Standard, Flat, and Popup styles through a DPI-aware WinForms adapter, share TextBox field metrics, align native selection heights, and round Win11 dropdowns while preserving System and High Contrast paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Fix ToggleSwitch System mouse geometry Keep modern toggle switches owner-drawn when FlatStyle.System is selected and use control bounds instead of requesting an unsupported native adapter. Cover every FlatStyle, Appearance, and VisualStylesMode interaction. Fixes dotnet/winforms#14754 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Preserve ambient VisualStylesMode serialization Base ShouldSerializeVisualStylesMode on the raw PropertyStore entry so Inherit emits no CodeDOM while explicit values round-trip through designer serialization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Document modern VisualStyles layout contracts Move affected property contracts into partial declarations and add adaptive-layout guidance for metric growth, fixed-bounds editors, GroupBox content geometry, and aligned TextBox/ComboBox rows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Preserve classic ComboBox selection metrics Apply native selection-field height overrides only while modern metrics are active, or while restoring a field that previously used them, so classic owner-drawn item bounds remain unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Update CheckBox System regression expectation Assert the fixed non-owner-drawn mouse-over geometry instead of retaining the previous unsupported-adapter exception expectation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Refine modern GroupBox styles Render Standard as a borderless rectangular surface, use an accent outline for Flat and an accent header for Popup, and select real installed Semibold faces without mutating ambient fonts. Align caption and content metrics with Padding and preserve the existing visual-settings tracker cleanup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Refine modern ComboBox styles and padding Reactivate designer serialization for the shipped Padding property, add a one-pixel framework inset, render rounded Standard and Popup frames plus a square Flat frame, and keep native edit/list content aligned across DPI, style, and layout changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Stabilize native GroupBox invalidation assertions Accept the native System-style handle recreation's platform-dependent zero-or-one invalidation while retaining exact expectations for owner-drawn styles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Land modern ComboBox VisualStyles work (unified field, clickable button, no flicker, classic-safe) Squashed from Net11/VisualStylesMode-Fixes onto the 05 VisualStylesMode base branch (the source of truth for VisualStyles). Includes: - Ambient visual-styles layout fix (VisualStylesMode stored/reported as Inherit; EffectiveVisualStylesMode via GetEffectiveVisualStylesMode(IsHighContrast)). - Centralized modern ComboBox native layout (per-handle baseline, absolute target state, idempotent applier) and the modern renderer refactor. - Modern ComboBox: WM_NCCALCSIZE unifies the field over the drop-down button; WM_NCHITTEST->HTCLIENT plus a press/release hit-test makes the button open the list; double-buffered paint removes adorner flicker; wider button and edit window inset so the edit child clears the rounded arcs. - New Control.VisualStylesModeChangeImpact.Recreate: ComboBox returns it when crossing the modern/classic boundary so the handle is recreated and classic behaves exactly as before. WM_NCCALCSIZE is gated off for Simple combos. The 05 base branch is a main-based feature slice and does not compile on its own (it references SystemVisualSettings from a sibling base); validation happens in the integration build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Align modern UpDownBase internal padding with other controls The modern (Net11+) UpDownBase content inset (ModernContentInset) used a flat 1px border-thickness term, so its edit and side-by-side buttons sat one pixel tighter inside the frame than a modern TextBoxBase (which uses the per-border-style border padding from ModernControlVisualStyles.GetFieldPadding). Switch to the same per-border-style constants so the internal padding matches: Fixed3D 3->4, None 2->3, FixedSingle unchanged at 3. Also document every metric in ModernControlVisualStyles with an XML summary, and update the UpDownBase modern-geometry tests to the new default (Fixed3D) inset of 4. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> (cherry picked from commit 1ba7f565f85d9a8ba93ab075c4faffa742b1fdd5) * Align TextBoxBase test with ClientAreaAnimations rename Follows the API Review board rename of SystemVisualSettingsCategories.Animations to ClientAreaAnimations (enum owned by the New Application API base). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Mask non-antialiased region corner artifacts on modern rounded chrome The modern VisualStyles rounded chrome (TextBox, UpDown, ComboBox, GroupBox) masks/clips its corners with a Region, which cannot be anti-aliased and leaves jagged pixels just outside the anti-aliased border. Add a shared ParentBackgroundRenderer.PaintRoundedBorderRegionMitigation helper that traces a 2px line in the parent background color immediately outside each rounded border, blending the artifact into the parent. Wire it into TextBoxBase, UpDownBase, ComboBox.ModernComboAdapter and GroupBox.Modern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Add SystemVisualSettingsTestScope test helper for renderer tests Branch 05's modern VisualStyles renderer tests (ComboBox, GroupBox, CheckBox ToggleSwitch, GroupBox accessibility) use SystemVisualSettingsTestScope to make system visual settings deterministic. The helper wraps branch 01's SystemVisualSettingsTracker.ResetForTesting and was previously only added during integration; define it in branch 05 where its consumers live. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Align NumericUpDown integration sizing assertion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Fix VisualStylesFocusBandHeight reference in modern TextBox NC paint OnNcPaint already computes focusBandHeight via GetVisualStylesFocusBandHeight(); the rounded focus-indicator call referenced a non-existent VisualStylesFocusBandHeight constant. Use the computed focusBandHeight value (already scaled) instead. This removes an integration-time repair so branch 05 is self-consistent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Add PropertyNames.SystemVisualSettings layout key The modern VisualStyles rendering (ComboBox/GroupBox/TextBox) triggers layout via LayoutTransaction.DoLayout(..., PropertyNames.SystemVisualSettings), but the key was only introduced during integration. Define it alongside VisualStylesMode so branch 05 is self-contained. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Add RaiseSystemVisualSettingsChanged to VisualStylesModePanel test helper TextBoxBaseTests invokes parent.RaiseSystemVisualSettingsChanged(...) on a VisualStylesModePanel, but the helper only exposed the raiser on the TextBox subclass. Add the matching seam to VisualStylesModePanel so the parent-driven settings-change tests compile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff * Mute modern ComboBox field surface when disabled (#14797) The modern ComboBox painted its field surface and DropDownList selection background with the control's BackColor regardless of Enabled, so a disabled ComboBox still showed its full custom BackColor/ForeColor. The button, border, and text already handled the disabled state; the surface fill did not. Add GetEffectiveFieldColor, which mutes the background (matching the existing disabled button/GroupBox treatment) when the control is disabled, and use it for the field surface and the DropDownList selection background. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Render BackgroundImage in modern GroupBox Card and Popup styles (#14779) The modern GroupBox renderers fill an opaque body surface (DrawModernCard fills frameBounds; DrawModernPopup fills the rounded body path), which painted over the BackgroundImage drawn by OnPaintBackground, so the image was invisible for FlatStyle Standard and Popup in VisualStylesMode.Net11. Composite the BackgroundImage back over the surface via a new PaintModernBackgroundImage helper (transparent back color so the surface tint is preserved around non-tiling layouts), clipped to the body area (and to the rounded frame path for Popup). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Fix modern GroupBox padding, DisplayRectangle and caption layout Make Padding affect only the child content area (DisplayRectangle), never the rendered adornments or caption text, and correct each FlatStyle's layout. - Padding no longer moves the caption text. Exception: Standard and Popup shift the caption horizontally by Padding.Left (LTR) / Padding.Right (RTL); the caption never moves vertically and Flat ignores Padding for text. - Standard (card): drop the internal horizontal and bottom content insets, so a docked child with Padding = 0 fills the entire card. DisplayRectangle reserves only the caption band plus its gap at the top. - Flat (outline): run the top border line along the caption text baseline (was the caption vertical middle), indent the caption by the corner radius, and set the top content inset to the font descent + 1px leeway so content clears the descenders. Left/right/bottom sit just inside the border. - Popup: 2px system inset on left/right/bottom and a 0px top gap so content is flush with the accent header rectangle; caption uses the Standard alignment rule on top of the header's horizontal padding. - Add GetModernCaptionMetrics (device-pixel ascent/descent from the caption font family metrics) plus GroupBoxPopupContentInset and GroupBoxFlatBaselineLeeway constants. Updated the modern DisplayRectangle unit test to the new per-style formulas and added coverage for the zero-padding card fill, the Flat baseline top inset, the Popup insets, and Padding not moving the caption vertically. All 968 GroupBox tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Integrate system visual settings with visual styles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Propagate ClientAreaAnimations rename to branch-05 consumers Integration-4 also merges the VisualStyles slice (branch 05), whose AnimatedControlRenderer and associated tests consume the renamed enum member. Update those references so the integration compiles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 * Isolate process-wide color mode test state Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Make animation mechanics tests deterministic Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Scope rapid toggle animation test settings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 * Restore shared system text scale lookup Reintroduce the consolidated accessibility text-scale helper dropped during Integration-3 replay so SystemVisualSettingsTracker and font scaling share one registry implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d * Remove stale KioskMode API entries from Integration-5 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Remove stale Form API entry after settings integration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Preserve classic TextBox preferred-size padding Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Remove trailing whitespace from high-risk review Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Make visual settings test scope deterministic Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Align modern ComboBox rendering tests with final layout model Preserve owner-drawn DropDownList content and validate recreated handles, child-bound padding, final chrome insets, and antialiased colors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Stabilize antialiased modern border color tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Update ComboBox integration test for handle recreation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Align NumericUpDown integration test with modern inset Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 * Correct modern GroupBox caption geometry Share Popup caption padding with Standard, lower Flat captions by the logical stroke, and make Flat border gaps symmetric around measured text. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40d0f0f7-a584-4167-9187-9d529b7c70f8 Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559 Copilot-Session: 24d81626-c337-40c8-a515-393ee8e9827d Copilot-Session: 64d20bbb-13df-4e59-8bcc-c307909b03f8 Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777 Copilot-Session: 9c3dc32b-7202-48c4-b0c7-f40a0a681ee2 Copilot-Session: 19883d86-6d5f-4d51-94c2-81d0bf3fc3ff Copilot-Session: 41e90924-3241-42a8-9556-71e100be7e59 Copilot-Session: 8c96a2a1-9a56-4ebe-a0d4-08297832eb45 Copilot-Session: a909fa48-8991-4d3a-8b90-617a4c026200 Copilot-Session: 225d4d4c-7dd7-46f1-9406-b30ff07bd8b5 Copilot-Session: 33fa13dc-4960-4c84-a4fb-d1ab91741b73 Copilot-Session: c352332b-4b81-4492-bcfc-9dec524c27c9 Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101
1 parent c8139b9 commit 8554492

174 files changed

Lines changed: 27863 additions & 1146 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Work-Order: Centralize ComboBox Modern Chrome State into an Idempotent Chokepoint
2+
3+
**Area:** WinForms Runtime — `VisualStylesMode` / .NET 11 visual modernization
4+
**Component:** `System.Windows.Forms.ComboBox` (modern `FlatStyle` rendering)
5+
**Branch baseline:** `KlausLoeffelmann/winforms` @ `d6ca49640903fa4f15be20b427f253bb940855d4` (`Net11/VisualStylesMode-Fixes`, rebased on `Net11/Integration-3`, upstream draft PR dotnet/winforms#14768)
6+
**Type:** Rearchitecture (bug-class elimination), supersedes point-fix follow-ups to the "1-pixel internal padding" work-order.
7+
8+
---
9+
10+
## 1. Problem Statement
11+
12+
The modern ComboBox chrome (`UsesModernComboAdapter == true`) mutates **three independent pieces of native state**:
13+
14+
1. `CB_SETITEMHEIGHT(-1)` — the native selection-field height,
15+
2. `EM_SETMARGINS` on the child edit HWND,
16+
3. `SetWindowPos` on the child edit (and, for `ComboBoxStyle.Simple`, the child list) HWND.
17+
18+
Each mutation has its own capture/restore bookkeeping (`_modernEditBaseBounds`, `_modernEditBaseClientSize`, `_modernSimpleListBaseBounds`, `_modernFieldHeightApplied`, `_modernHandleInitialized`), and the mutations are applied from **many triggers** (`OnVisualStylesModeChanged`, `OnHandleCreated`, `OnFontChanged`, `OnPaddingChanged`, `OnSystemVisualSettingsChanged`, `RescaleConstantsForDpi`, `WM_SETFONT` on the child, `WM_WINDOWPOSCHANGED` for Simple, `UpdateItemHeight`, the `FlatStyle` setter) in trigger-specific orderings that depend on what `base.*` does in between.
19+
20+
This produces an entire **class** of state-desynchronization bugs. Four confirmed instances against the pinned baseline:
21+
22+
### Defect A — Vertical/horizontal inset asymmetry (edit overshoots the rounded border)
23+
`UpdateModernEditMargins` applies `Fixed3DBorderPadding (2) + InternalChromeInset (2) + ComboBoxStyleInset (1)` = 5 logical px **horizontally** via `EM_SETMARGINS`, but `UpdateModernEditBounds` insets the edit **vertically** by only `ComboBoxStyleInset (1) + Padding.Top/Bottom`. The rounded border ring consumes ~3 px vertically (Fixed3D zone + AA stroke), so with `Padding.Empty` the edit client overlaps the border curve. `Padding = 2` masks it, which confirms the diagnosis.
24+
25+
### Defect B — `EM_SETMARGINS` never reset on modern → classic
26+
In `ComboBox.OnVisualStylesModeChanged`, `RestoreAndResetModernEditBounds()` empties `_modernEditBaseBounds` **before** the trailing `UpdateModernEditMargins()` call; that method's guard `(!UsesModernComboAdapter && _modernEditBaseBounds.IsEmpty)` then early-returns, so the classic edit child keeps the 5 px modern margins.
27+
28+
### Defect C — Restore targets `COMBOBOXINFO.rcItem`, not the edit's native bounds
29+
The DropDown path seeds `_modernEditBaseBounds` from `rcItem` (the combo's selection-field rect) but restores the **edit HWND** to that rect. The edit natively sits *inside* `rcItem` with a theme inset. The Simple path already does this correctly via `GetChildBounds(comboBoxInfo.hwndItem)`; the DropDown path does not.
30+
31+
### Defect D — Delta-based `CB_SETITEMHEIGHT` is order-fragile and non-idempotent
32+
`ApplyPreferredFieldHeight` computes `heightDelta = preferredHeight - Height` and applies it **relative** to the current item height. Before this runs, `Control.OnVisualStylesModeChanged` (`Metrics` impact) has already executed `RequestLayout`, `UpdateStyles`, and `RefreshVisualStylesModeNonClientArea` (SetWindowPos w/ `SWP_FRAMECHANGED`). Whenever any of these reconciles `Height` first — anchored controls, `TableLayoutPanel` cells, designer behavior service, or **deserialization**, where the mode transition occurs before handle creation and `Height` is already set to the target — the delta collapses to `0` and the native selection-field height silently keeps the previous mode's value. Because the math is relative, each round-trip can accumulate error. This is the primary suspect for the classic missing drop-down button and the misplaced button/frame remnants after classic → modern round-trips, and it fully explains why every deserialization pass re-triggers the corruption.
33+
34+
---
35+
36+
## 2. Target Architecture
37+
38+
Replace the trigger-specific mutation choreography with **one idempotent chokepoint**, mirroring the `EffectiveVisualStylesMode` chokepoint pattern already established for the .NET 11 work: many inputs, one authoritative computation, one applier.
39+
40+
### 2.1 Core principle
41+
42+
> The chokepoint computes the complete **target native state absolutely** from current inputs and applies it. It never reads back its own previous output to decide the next one, and calling it N times in any order after any trigger yields the same native state as calling it once.
43+
44+
There is no separate "restore" path: applying the chokepoint while `UsesModernComboAdapter == false` *is* the restore, because the target state for classic mode is the captured native baseline.
45+
46+
### 2.2 New shape (in `ComboBox.Modern.cs`)
47+
48+
```csharp
49+
/// <summary>
50+
/// Captures the native, unmodified child layout of the ComboBox once per handle
51+
/// lifetime, before any modern chrome mutation is applied.
52+
/// </summary>
53+
private readonly struct NativeComboBaseline
54+
{
55+
public int SelectionFieldItemHeight { get; init; }
56+
public Rectangle EditBounds { get; init; }
57+
public Rectangle SimpleListBounds { get; init; }
58+
public Size ClientSize { get; init; }
59+
60+
public bool IsCaptured
61+
=> !EditBounds.IsEmpty || SelectionFieldItemHeight > 0;
62+
}
63+
64+
/// <summary>
65+
/// The complete target state for the ComboBox's native children under the
66+
/// current effective visual styles mode.
67+
/// </summary>
68+
private readonly struct ModernComboTargetState
69+
{
70+
public int SelectionFieldItemHeight { get; init; }
71+
public Padding EditMargins { get; init; }
72+
public Rectangle EditBounds { get; init; }
73+
public Rectangle SimpleListBounds { get; init; }
74+
}
75+
76+
/// <summary>
77+
/// Single chokepoint. Computes the absolute target state for item height,
78+
/// edit margins, and child bounds from the current inputs and applies it.
79+
/// Idempotent; safe to call from any trigger in any order.
80+
/// </summary>
81+
private void ApplyModernComboLayout();
82+
```
83+
84+
### 2.3 Rules
85+
86+
1. **Baseline capture happens exactly once per handle lifetime**, in `OnHandleCreated`, *before* the first mutation: native default `CB_GETITEMHEIGHT(-1)`, `GetChildBounds(hwndItem)` (fixes Defect C — use child bounds, never `rcItem`), `GetChildBounds(hwndList)` for Simple, and the `ClientSize` at capture time. Cleared in `OnHandleDestroyed`.
87+
2. **Item height is computed absolutely** (fixes Defect D):
88+
- Modern: derive the target selection-field height from `ModernPreferredHeight` minus the native frame, measured against the **HWND** (`GetWindowRect`), never against `Control.Height` bookkeeping.
89+
- Classic: target = `NativeComboBaseline.SelectionFieldItemHeight`.
90+
- Apply only when the current native value differs (read-compare-write, so repaint/relayout storms are avoided while idempotency is preserved).
91+
3. **Edit margins are computed absolutely**: modern = the existing `Fixed3DBorderPadding + InternalChromeInset + ComboBoxStyleInset` formula plus `Padding.Left/Right`; classic = `0` (fixes Defect B — restore is just "apply classic target").
92+
4. **Vertical edit insets use the same chrome formula as the horizontal margins** (fixes Defect A): `topInset`/`bottomInset` = scaled `Fixed3DBorderPadding + ComboBoxStyleInset` (+ `Padding.Top/Bottom`), sourced from a single `GetModernChromeInsets()` helper so the border geometry (`CreateFieldPath`, `ClearNativeFrame`) and the child layout can never diverge again. If the "≥ 1 px internal padding" requirement from the previous work-order needs adjusting, it is adjusted **here, in one place**.
93+
5. **All triggers call only the chokepoint.** `OnVisualStylesModeChanged`, `OnHandleCreated`, `OnFontChanged`, `OnPaddingChanged`, `OnSystemVisualSettingsChanged`, `RescaleConstantsForDpi`, child `WM_SETFONT`, `WM_WINDOWPOSCHANGED` (Simple), `UpdateItemHeight`, and the `FlatStyle` setter each reduce to: invalidate caches as needed → `ApplyModernComboLayout()`. Ordering relative to `base.*` calls no longer matters, because the chokepoint reads only current inputs.
94+
6. **Reentrancy guard lives inside the chokepoint** (`_adjustingModernChildBounds` moves in; callers never manage it).
95+
7. **Delete** `RestoreModernEditBounds`, `RestoreAndResetModernEditBounds`, `ResetModernEditBounds`, `ResizeModernSimpleBaseBounds`, `UpdateModernEditMargins`, `UpdateModernEditBounds`, `UpdateModernSimpleEditBounds`, `ApplyPreferredFieldHeight`'s delta logic, and the fields `_modernEditAppliedBounds`, `_modernEditBaseBounds`, `_modernEditBaseClientSize`, `_modernFieldHeightApplied`, `_modernSimpleListBaseBounds`. Replaced by `NativeComboBaseline` + the chokepoint.
96+
8. `WinFormsApplicationBuilder`/host concerns are out of scope; this is runtime-internal. Public API surface is unchanged (`FlatStyle`, `Padding`, `PreferredHeight` semantics stay as shipped in Integration-3).
97+
98+
### 2.4 Explicit non-goals
99+
100+
- No changes to `ModernComboAdapter` painting itself except consuming `GetModernChromeInsets()` for its geometry constants.
101+
- No changes to the `EffectiveVisualStylesMode` propagation in `Control` — the chokepoint must work with the existing `Metrics`/`Repaint` impact model as-is.
102+
- No behavioral change for `FlatStyle.System` (remains fully native) or for classic `Flat`/`Popup` (existing `FlatComboAdapter`).
103+
104+
---
105+
106+
## 3. Tasks
107+
108+
| # | Task | Notes |
109+
|---|------|-------|
110+
| 1 | Introduce `NativeComboBaseline` capture in `OnHandleCreated`; clear in `OnHandleDestroyed`. | Capture **before** dark-mode theming and before any `CB_SETITEMHEIGHT`. |
111+
| 2 | Introduce `GetModernChromeInsets()` shared by adapter geometry and child layout. | Single source of truth for Defect A. |
112+
| 3 | Implement `ComputeModernComboTargetState()` (pure, absolute). | Inputs: `EffectiveVisualStylesMode`, `FlatStyle`, `DropDownStyle`, `Font`/`FontHeight`, `Padding`, `DeviceDpiInternal`, `SystemVisualSettings`, `RightToLeft`, baseline. |
113+
| 4 | Implement `ApplyModernComboLayout()` applier with read-compare-write per state item and internal reentrancy guard. | Item height via HWND-measured frame, not `Control.Height`. |
114+
| 5 | Reroute all triggers listed in Rule 5 through the chokepoint; delete legacy methods/fields per Rule 7. | `OnVisualStylesModeChanged` body shrinks to cache invalidation + `base` + chokepoint + `RefreshModernDropDownCornerPreference`. |
115+
| 6 | Verify `DrawMode.OwnerDrawFixed/Variable` interplay: `UpdateItemHeight`'s explicit `CB_SETITEMHEIGHT` calls must not fight the chokepoint. | Owner-draw item heights own indices ≥ 0; chokepoint owns index −1 in Normal mode; define precedence for owner-draw −1. |
116+
| 7 | Add a debug assertion helper that dumps `CB_GETITEMHEIGHT(-1)`, `COMBOBOXINFO.rcItem/rcButton`, and edit HWND bounds — used for the acceptance runs below. | Also resolves the open question whether the missing classic arrow is a Defect D consequence (degenerate `rcButton`) or an overlap. |
117+
| 8 | Consider a `WFCC` `ComponentChange` entry if any observable classic-mode behavior shifts (e.g., corrected edit inset after round-trip). | Only if acceptance runs surface an observable delta vs. .NET 10 classic. |
118+
119+
---
120+
121+
## 4. Acceptance Criteria
122+
123+
1. **Round-trip invariance:** `Classic → Net11 → Classic` repeated 10× (runtime *and* designer-hosted) yields native state byte-identical to a freshly created classic ComboBox: item height, edit HWND bounds, `EM_GETMARGINS`, `rcButton` non-degenerate, drop-down arrow visible.
124+
2. **Order independence:** Deserialization sequences that set `FlatStyle`/`Padding`/`Font`/mode in any order, before or after handle creation, converge to the same state. Specifically: mode transition before handle creation must not zero out the item-height adjustment (Defect D repro).
125+
3. **Layout-container safety:** Combo inside `TableLayoutPanel` and with `Anchor = Top|Bottom` survives mode round-trips without frame remnants or misplaced button (Screenshot 4/5 repro).
126+
4. **No overshoot at `Padding.Empty`:** the edit client rect is fully contained within the rounded field path at 100 %, 150 %, 200 % DPI (Screenshot 1 repro). `Padding` values add on top and never subtract.
127+
5. **Simple style:** resize + mode round-trips keep edit/list stacked correctly; no drift of `_modernSimpleListBaseBounds`-equivalent state.
128+
6. **RTL:** all of the above with `RightToLeft.Yes`.
129+
7. **Idempotency probe:** calling `ApplyModernComboLayout()` 5× consecutively produces zero additional native messages after the first call (read-compare-write verified via message trace).
130+
8. Existing modern paint tests (adapter geometry, chevron, `DropDownList` text) pass unchanged.
131+
132+
---
133+
134+
## 5. Risks / Open Questions
135+
136+
- **Native height authority:** for non-Simple styles the native control owns window height derived from item height; the chokepoint must treat `CB_SETITEMHEIGHT(-1)` as the *only* height lever and let `Control.Height` bookkeeping follow via `WM_WINDOWSPOSCHANGED`, never the reverse. Any remaining `Height = preferredHeight` assignments should be audited for redundancy.
137+
- **Owner-draw precedence** (Task 6) needs an explicit decision; proposal: in `DrawMode != Normal`, the chokepoint does not touch index −1 and modern metrics derive the field height from the owner-draw value instead.
138+
- **Classic missing-arrow root cause** is expected to be Defect D but must be confirmed via the Task 7 dump before closing; if it turns out to be an overlap issue, Task 1's child-bounds baseline already covers it.
139+
140+
---
141+
142+
## 6. References (pinned)
143+
144+
- `ComboBox.cs`, `ComboBox.Modern.cs`, `ComboBox.ModernComboAdapter.cs`, `ComboBox.FlatComboAdapter.cs`, `Rendering/ModernControlVisualStyles.cs` — all at
145+
`https://github.com/KlausLoeffelmann/winforms/blob/d6ca49640903fa4f15be20b427f253bb940855d4/src/System.Windows.Forms/System/Windows/Forms/...`
146+
- `Control.OnVisualStylesModeChanged` / `VisualStylesModeChangeImpact.Metrics` handling — `Control.cs`, same SHA (~lines 7060–7110).
147+
- Upstream draft PR: dotnet/winforms#14768 (`Net11/Integration-3`).

0 commit comments

Comments
 (0)