[NO MERGE] Add flicker-free UI mutation APIs#14735
Open
KlausLoeffelmann wants to merge 18 commits into
Open
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 27022e2a-9eb8-4f58-9bfa-e79ca0d6c559
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rface Splits DeferLocationChange out of this branch entirely (postponed pending an anchor-layout-engine integration fix; tracked separately in #12) and reworks ISupportSuspendPainting / ISupportSuspendRelocation on Control to match the final API shape agreed in dotnet#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>
…inel Matches the final API shape agreed in dotnet#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>
Adds Microsoft.VisualBasic.ApplicationServices.ApplyApplicationDefaultsEventArgs.FormRevealMode, following the exact same pattern already established for ColorMode and HighDpiMode in that class, per dotnet#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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 20883488-cf1e-4ad3-a681-0724e9f16777
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
KlausLoeffelmann
force-pushed
the
Net11Api_03_ImproveControlRendering
branch
from
July 18, 2026 08:27
67dd34f to
d26d86f
Compare
This was referenced Jul 18, 2026
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 78934db)
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
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
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
…rst 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
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
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 86cc3454-1c71-4d7f-a766-231b55099101
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #14585.
Contributes to #14694.
FormRevealModeand application-default support to reduce initial form flash.Microsoft Reviewers: Open in CodeFlow