Repository navigation
feat: add floating region views for WPF and Avalonia - #55
Merged
Merged
Conversation
- Make ViewPlacementCoordinator.EnterAsync reentrant per logical async call chain to fix a deadlock when a navigation callback (e.g. OnNavigatedToAsync) triggers a placement change on the same region; exposes IsHeld() for lease-contract enforcement. - Make WeakUnloadObserver.Subscribe idempotent so docking a floated view back no longer double-subscribes its unload handler. - Respect RegionPlacementItem.WasSelected on Attach instead of forcing activation, and only correct selection on a failed restore when it was actually disturbed. - Set up the indicator host unconditionally at the start of CreateNavigateTask so a failed or externally-activated navigation always has a usable IndicatorHost. - Add the missing Selected ?? Items.LastOrDefault() fallback to TabRegion/TabbedPageRegion.Capture() to match ItemsRegion behavior. - Fail fast in GetContentHost when an indicator host doesn't support content detachment, instead of silently corrupting the visual tree. - Enforce the documented placement-lease contract in RegionBase.RestorePlacementAsync via ViewPlacementCoordinator.IsHeld. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AvaloniaFloatingWindowHostFactory previously required Avalonia's classic desktop lifetime and threw NotSupportedException otherwise, so FloatAsync was unusable on browser/WASM and mobile single-view apps. It now selects the host per ApplicationLifetime: classic desktop still gets a real OS Window, while single-view apps get a new AvaloniaOverlayFloatingWindowHost that renders the floating content as a draggable, resizable in-page overlay panel (via Avalonia's OverlayLayer) with the same Dock/Close contract as the native window host. Verified with a new headless E2E test and manually in Sample.Avalonia.Browser via dotnet run + Chrome: float, drag, dock, and close all round-trip correctly with no console errors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
MainWindow.axaml previously hosted its own "Floating: current MainRegion view" button + description around <views:MainView />, so the demo only existed on classic desktop; MainView (the shared root used directly by Avalonia's single-view lifetime on browser/WASM, Android and iOS) never had it. Move the button and its FloatMainRegion_Click handler into MainView itself, and have MainWindow construct MainView in code and forward its IViewPlacementService instead of duplicating the header. Desktop, browser, Android and iOS now show the identical set of floating samples (MainRegion, TabRegion, ChildContentRegion, ItemsRegion, ListBoxRegion), with desktop's existing behavior as the reference. Verified in Sample.Avalonia.Browser via dotnet run + Chrome: the MainRegion float/dock button now shows on the home page and round-trips correctly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AsyncNavigation.E2E.Tests (Avalonia.Headless.XUnit) already exercises floating/docking/visual-state behavior but was never wired into CI - only tests/AsyncNavigation.Tests ran, and the sample jobs just build, never test. Add a test-e2e job mirroring the existing test job's 3-OS matrix. Retarget the test project from net10.0-windows to net10.0: nothing in it uses a Windows-only API, and Avalonia.Headless is cross-platform by design, so the Windows-only TFM was an unnecessary constraint blocking Linux/macOS runs. Verified locally (Windows) in both Debug and Release. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Sep 30, 2026
NeverMorewd
added a commit
that referenced
this pull request
Oct 10, 2026
…#58) Fixes 5 of the 6 previously-deferred, pre-existing (not introduced by the earlier floating-feature fixes) review findings; the 6th (ViewManager.AddView's UpdateDuplicateKey path overwriting a still-floating view's cache slot) turned out to be intended, tested behavior once verified against CloseOldInstance_DoesNotRemoveNewInstanceCacheOrHistory, so it was left as-is. - RegionNavigationService.OnAfterNavigationAsync: call OnNavigatedFromAsync before the pipeline's cancellation check throws, if cancellation raced in right after OnNavigatedToAsync succeeded - otherwise the view's lifecycle state (activated, never told it left) goes out of sync with the region reverting. Covered by a new regression test that reproduces the race via a test double's activation hook. - WeakUnloadObserver.Subscribe: take Func<INavigationAware, Task> instead of Action<INavigationAware> and await it, so its one caller's async lambda is a real awaited continuation instead of async-void with unobservable exceptions. - ViewManager: Remove(key, dispose) now returns bool (true if it actually removed something) instead of silently no-op'ing when the entry is pinned by a floating view, so callers can tell the two cases apart. - ViewManager.TrimCache: resume scanning from where the previous eviction left off instead of restarting from the LRU tail every iteration, avoiding O(evictions * pinned-views) work when floating views sit at the tail. - Extracted the "cancel the window's close, then raise CloseRequested" state machine - duplicated near-verbatim between AvaloniaFloatingWindowHost and WpfFloatingWindowHost - into a shared FloatingWindowCloseGuard in AsyncNavigation.Floating, so this exact subtle dance only needs fixing once. Verified: dotnet test tests/AsyncNavigation.Tests (158 passed) and tests/AsyncNavigation.E2E.Tests (9 passed), Debug and Release, plus a full solution build - all green. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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
Add opt-in floating region views for WPF and Avalonia. A rendered view can move into a separate window and dock back without creating another view instance. Window close ends the floating session; a separate Dock to region button restores it.
Compatibility
Floating support requires explicit registration. Restore the public NavigationAwareBase with its original API and default behavior, marked obsolete with a recommendation to implement INavigationAware directly. Update the English and Chinese README examples accordingly.
Clear non-floating cache entries before invoking disposal so a throwing Dispose cannot leave unrelated old entries cached. Floating views remain protected. Existing IPlatformService and IRegionManager interface changes already on main are outside this PR.
Validation
Sample builds report existing NU1507 package-source warnings. The full multi-platform solution was not built.
Mobile CI
Explicitly install Android platform-tools instead of the setup action's obsolete tools default. Raise the iOS sample's minimum supported OS from 13 to 15 in both the project and Info.plist to match the CI workload. These changes affect sample/CI configuration, not library target frameworks.