docs/architecture/cross-cutting/navigation.md
WPF UI v4.2.0 | Cross-Cutting Concern
The WPF UI navigation system provides page-based navigation within NavigationView, with support for page caching, back stack management, transition animations, and lifecycle callbacks. It integrates with Microsoft.Extensions.DependencyInjection for type-based page resolution.
The following sequence diagram shows the complete flow from a NavigationService.Navigate() call through to the page being displayed with transition animations.
sequenceDiagram
participant Consumer as Consumer Code
participant NavService as NavigationService
participant NavView as NavigationView
participant Provider as INavigationViewPageProvider
participant Cache as Page Cache
participant Frame as Frame
participant OldPage as Old Page (INavigationAware)
participant NewPage as New Page (INavigationAware)
participant Animator as TransitionAnimationProvider
Consumer->>NavService: Navigate(typeof(MyPage))
NavService->>NavView: NavigateInternal(pageType)
NavView->>NavView: Check if same page (skip if current)
NavView->>Provider: GetPage(pageType)
Provider->>Provider: Resolve via IServiceProvider or Activator
alt NavigationCacheMode.Enabled or Required
Provider->>Cache: Check cache for pageType
Cache-->>Provider: Cached instance or null
alt Cache hit
Provider-->>NavView: Return cached page
else Cache miss
Provider->>Provider: Create new instance
Provider->>Cache: Store in cache
Provider-->>NavView: Return new page
end
else NavigationCacheMode.Disabled
Provider->>Provider: Create new instance (always)
Provider-->>NavView: Return new page
end
NavView->>OldPage: OnNavigatedFrom()
NavView->>Frame: Navigate(newPage)
Frame->>Frame: Update Content
NavView->>NewPage: OnNavigatedTo()
NavView->>Animator: ApplyTransition(frame, transition)
Animator->>Animator: Check HardwareAcceleration.RenderingTier
alt Tier >= 2 (hardware accelerated)
Animator->>Frame: Apply Storyboard (FadeIn/SlideBottom/etc.)
else Low rendering tier
Animator-->>NavView: Skip animation
end
NavView->>NavView: Push to back stack
NavView->>NavView: Update selected menu item
NavView-->>Consumer: Navigation complete
NavigationView supports three caching strategies via the NavigationCacheMode property on individual pages. The cache is maintained per-type within the INavigationViewPageProvider implementation.
stateDiagram-v2
[*] --> PageRequested: Navigate(pageType)
state PageRequested {
[*] --> CheckCacheMode
state CheckCacheMode <<choice>>
CheckCacheMode --> CacheDisabled: Disabled
CheckCacheMode --> CacheEnabled: Enabled
CheckCacheMode --> CacheRequired: Required
state CacheDisabled {
[*] --> CreateNew_D: Always create new instance
CreateNew_D --> ReturnPage_D: Return new page
}
state CacheEnabled {
[*] --> LookupCache_E: Check cache
LookupCache_E --> ReturnCached_E: Cache hit
LookupCache_E --> CreateAndCache_E: Cache miss
CreateAndCache_E --> ReturnPage_E: Store and return
ReturnCached_E --> ReturnPage_E: Return cached
}
state CacheRequired {
[*] --> LookupCache_R: Check cache
LookupCache_R --> ReturnCached_R: Cache hit (guaranteed after first)
LookupCache_R --> CreateAndCache_R: First request only
CreateAndCache_R --> ReturnPage_R: Store and return
ReturnCached_R --> ReturnPage_R: Return cached
}
}
PageRequested --> PageDisplayed: Page resolved
PageDisplayed --> [*]
| Mode | First Visit | Subsequent Visits | Page State | Use Case |
|---|---|---|---|---|
| Disabled | New instance | New instance | Lost on navigate away | Forms, transient views |
| Enabled | New instance | Cached instance (if available) | Preserved while cached | Dashboard, lists |
| Required | New instance | Always cached instance | Always preserved | Settings, stateful views |
Thin wrapper around INavigationView that provides a service-oriented API for navigation. Registered in DI as INavigationService.
Key methods:
Navigate(Type pageType) — Navigate to a page by typeNavigate(string pageTag) — Navigate to a page by tagGoBack() — Navigate to the previous page in the back stackSetNavigationControl(INavigationView) — Bind to a NavigationView instanceAbstraction for page instance resolution. Two implementations:
DependencyInjectionNavigationViewPageProvider (from Wpf.Ui.DependencyInjection) — resolves pages via IServiceProviderLifecycle interface for pages that need to respond to navigation events:
OnNavigatedTo() — Called when the page becomes the active viewOnNavigatedFrom() — Called when the page is navigated away fromTransitionAnimationProvider applies entry animations to navigated pages. Available transitions: FadeIn, FadeInFromBottom, SlideFromBottom, SlideFromRight, SlideFromLeft. Animations are skipped when HardwareAcceleration.RenderingTier < 2.
For hosted applications using Microsoft.Extensions.Hosting:
// In Program.cs or Startup
services.AddNavigationViewPageProvider<DependencyInjectionNavigationViewPageProvider>();
services.AddSingleton<INavigationService, NavigationService>();
// Pages registered in DI
services.AddTransient<DashboardPage>();
services.AddTransient<SettingsPage>();
The DependencyInjectionNavigationViewPageProvider resolves pages from the DI container, respecting their registered lifetime (Transient, Scoped, Singleton).
NavigationView maintains an internal back stack of previously visited page types. The GoBack() operation pops the most recent entry and navigates to it. The back stack is cleared when navigating to a page that is already in the stack (cycle prevention).
NavigationService directly; hosted apps use DI. Both paths are supported.INavigationViewPageProvider, not in NavigationView. This allows DI-managed lifetimes to control cache behavior.NavigationService does not marshal calls.