Add ThemeManager, JSON themes and animated transitions#17
Merged
Conversation
Record application lifetime, dispatcher affinity, immutable resolution, Brush ownership, and resource precedence. Specify atomic commit and rollback ordering, scheduler-only transitions, strict JSON trust boundaries, Designer behavior, compatibility, and platform limitations.
Add mutable definitions, typed semantic and custom tokens, single-base inheritance, immutable resolved snapshots, built-in Light/Dark themes, validation diagnostics, and strict schema-v1 System.Text.Json serialization. Commit manager-owned resources atomically on the UI dispatcher with rollback and legacy Theme projection. Integrate scheduler-only color, numeric, solid, and compatible gradient transitions with replacement, cancellation, reduced motion, lifecycle handling, diagnostics, Designer isolation, and Windows preference providers.
Cover definitions, inheritance, immutable Brush ownership, resource precedence, dynamic refresh, Designer behavior, JSON round trips and security limits, atomic rollback, dispatcher affinity, and safe failures. Exercise scheduler-driven colors, numeric resources, solid and gradient geometry/stops/transforms, rapid replacement, stale handles, cancellation, motion policies, observer faults, lifecycle pause/resume, no-host behavior, and orphan cleanup without Thread.Sleep.
Add an isolated ControlGallery page for immediate and animated Light/Dark switches, rapid replacement, cancellation, scheduler policy toggles, inherited JSON themes, safe validation failures, semantic values, Brushes, metrics, and diagnostics. Restore scheduler policy and event subscriptions on unload, and keep the template-reference DemoApp unchanged.
Document built-ins, typed and custom tokens, inheritance, immutable snapshots, Brush clone boundaries, resource precedence, atomic event ordering, transitions, diagnostics, strict schema-v1 JSON, security limits, and the interactive checklist. Update architecture, dynamic-resource precedence, roadmap, Windows/experimental Android limitations, migration guidance, known limitations, and draft 1.9.0 notes without changing package versions.
Refresh complete open-window control trees after atomic theme commits and coalesce invalidations into one platform repaint per window. Preserve live interaction state, keep animation frames visual-only, and make transition completion observable after the completion event. Add deterministic regression coverage for resources, nested and multiple windows, state preservation, animation ticks, subscriptions, and idle cleanup.
ProGraMajster
marked this pull request as ready for review
July 23, 2026 16:12
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.
Summary
Adds a production-oriented, application-wide ThemeManager for ModernFormsNext with typed, inheritable themes, strict JSON import/export, atomic resource publication, and optional animated transitions driven by the existing animation scheduler.
Architecture
ModernFormsNext/Theming.ThemeManagersingleton, a registry of immutable resolved snapshots, and versioned theme definitions.Themeprojection are swapped atomically. Observer failures are surfaced without leaving partially applied framework state, and commit failures roll back.Public API
The change introduces:
ThemeManager,ThemeManagerOptions, apply results, diagnostics, events, transition handles, and cancellation/replacement policies.ThemeDefinition,ThemeResolvedSnapshot,ThemeVariant, typed token/value records, token counts, validation results, and security limits.ThemeJsonSerializerwith sync/async string, stream, and file APIs.Application.ThemeResources, a read-only application theme-resource surface.IPlatformThemeSettingsfor backend-provided system theme and reduced-motion preferences.All new public and protected APIs include XML documentation. The usage guide contains code-first examples and migration guidance.
JSON schema and security
docs/theme-json-schema.md.Inheritance and resources
Theme lookup now follows:
Control -> nearest parent -> window -> Application.Resources -> Application.ThemeResources -> captured CLR fallbackTheme resources remain below application overrides, so application resources keep precedence. Definitions are deeply cloned and resolved snapshots are immutable/read-only; mutable brushes are cloned at boundaries. Custom resources use a closed typed union and derived themes must preserve the inherited resource kind.
Transitions
AnimationSchedulerandBrushAnimationPlan.IgnoreNewpreserves the active transition.Platform behavior
Designer behavior
Designer-facing metadata hides complex dictionaries from property-grid expansion, while serialization and cloning remain deterministic. Designer tests verify that theme operations do not create unintended runtime side effects.
Samples
A dedicated ControlGallery ThemeManager panel demonstrates:
ModernFormsNext.DemoAppwas not changed; it remains the default template/reference application.Tests and validation
Deterministic tests cover the model, inheritance, schema, security limits, atomic apply/rollback, UI-thread commit, latest-wins behavior, cancellation, transitions, resources, lookup precedence, legacy compatibility, designer safety, platform fallbacks, and diagnostics. No
Thread.Sleepis used.Local validation completed:
dotnet restore .\ModernFormsNext.slnx --force --no-cachegit diff --check origin/master...HEADExisting solution warnings remain, including dependency advisories/compatibility warnings in the Visual Studio extension, legacy nullability/obsolete API warnings, platform analyzer warnings, and the Android 16 KB page-size warning. A no-incremental warning audit found no warning lines in the new ThemeManager-related areas.
No version was bumped and no package was published.
Documentation
Known limitations
Manual verification checklist
UI refresh regression fix
Root cause
The committed legacy
Themevalues and staticControlStyledefaults were updated correctly, butForm.OnThemeChangedvisited only the adapter's immediate children andControl.OnThemeChangedonly marked controls dirty without scheduling a platform repaint. Nested controls therefore resolved the new values only after hover, click, focus, resize, or another later state invalidation. Dynamic-resource setters invalidated some controls independently, which made the failure appear partial.Propagation and invalidation
The UI-thread commit now follows one coherent order:
resource snapshot -> ResourceDictionary notifications/setters -> legacy Theme/ControlStyle refresh -> recursive refresh of every open form and the active popup -> one batched platform repaint per affected windowThe complete explicit and framework-owned implicit control tree is visited. Normal, Hover, Pressed, Focused, Disabled, and control-specific state remain unchanged and are resolved again against the committed style values. The generic path performs visual invalidation only; it does not force a full layout. A control may still request its existing targeted layout path when theme typography or metrics affect cached measurement.
Dynamic-resource subscriptions continue to update controls without recreation, and their setter invalidations join the same window batch. Regression coverage verifies that reparenting does not duplicate subscriptions and that disposed controls stop receiving updates.
Animated transitions
Each scheduler tick updates brush/color resources and the legacy projection inside a visual-only invalidation batch. Every affected window receives one platform repaint request per tick, while control-specific layout/cache hooks are bypassed. At completion the active animation count returns to zero and the tick source stops. The completion event is delivered before the public completion task is released, so awaited state is stable.
Regression coverage
Ten deterministic tests cover immediate Normal refresh; preserved Hover; Pressed, Focused, and Disabled states; resource invalidation without mouse input; nested trees; multiple windows; successive animation ticks; one coherent immediate refresh; subscription/disposal cleanup; and scheduler/invalidation idle cleanup.
Final local validation:
Closes #7
Closes #8
Closes #9
Closes #10