Files
YMhut-box-C-/参考/wpfui-main/docs/architecture/views/logical-architecture.md
T
2026-07-06 23:05:40 +08:00

29 KiB

Logical Architecture

This document describes the logical architecture of WPF UI v4.2.0, a C# WPF control library implementing Microsoft Fluent Design System. It covers module dependencies, internal layer organization, control authoring patterns, cross-cutting concerns, and the multi-targeting strategy.


1. Module/Package Dependency Diagram

The WPF UI solution consists of ten projects organized around a core library (Wpf.Ui) with satellite packages for optional functionality.

graph TD
    Abstractions["<b>Wpf.Ui.Abstractions</b><br/>NuGet: WPF-UI.Abstractions<br/>Zero-dependency interfaces:<br/>INavigationViewPageProvider,<br/>INavigationAware, INavigableView&lt;T&gt;<br/><i>Targets: netstandard2.0/2.1,<br/>net462, net8.0, net9.0, net10.0</i>"]

    Core["<b>Wpf.Ui</b><br/>NuGet: WPF-UI<br/>77+ controls, theming, services,<br/>Win32 interop<br/><i>Targets: net10.0-windows,<br/>net9.0/8.0-windows,<br/>net481, net472, net462</i>"]

    DI["<b>Wpf.Ui.DependencyInjection</b><br/>NuGet: WPF-UI.DependencyInjection<br/>MS DI integration<br/><i>Targets: netstandard2.0/2.1,<br/>net462, net8.0, net9.0, net10.0</i>"]

    Tray["<b>Wpf.Ui.Tray</b><br/>NuGet: WPF-UI.Tray<br/>System tray icons via Shell32<br/><i>Targets: net10.0/9.0/8.0-windows,<br/>net481, net472, net462</i>"]

    Syntax["<b>Wpf.Ui.SyntaxHighlight</b><br/>NuGet: WPF-UI.SyntaxHighlight<br/>Code syntax highlighting (WIP)<br/><i>Targets: net10.0/9.0/8.0-windows,<br/>net481, net472, net462</i>"]

    Toast["<b>Wpf.Ui.ToastNotifications</b><br/>NuGet: WPF-UI.ToastNotifications<br/>Toast notifications (STUB,<br/>all throw NotImplementedException)<br/><i>Targets: net10.0/9.0/8.0-windows,<br/>net481, net472, net462</i>"]

    Gallery["<b>Wpf.Ui.Gallery</b><br/>Demo/showcase app<br/>MVVM with CommunityToolkit.Mvvm<br/><i>Target: net10.0-windows10.0.26100.0</i>"]

    FlaUI["<b>Wpf.Ui.FlaUI</b><br/>NuGet: WPF-UI.FlaUI<br/>Test automation helpers<br/><i>Targets: net10.0/9.0/8.0-windows,<br/>net481</i>"]

    FontMapper["<b>Wpf.Ui.FontMapper</b><br/>Build tool: icon enum generation<br/>from FluentSystemIcons JSON<br/><i>Target: net10.0</i>"]

    Extension["<b>Wpf.Ui.Extension</b><br/>VS 2022 VSIX extension<br/>Project templates (Blank, Compact, Fluent)<br/><i>Target: net481 (VSIX SDK)</i>"]

    %% Dependency arrows (arrow points from dependent to dependency)
    Core --> Abstractions
    DI --> Abstractions
    DI -.->|"Microsoft.Extensions.<br/>DependencyInjection.Abstractions 3.1.0"| ExtDI["Microsoft.Extensions.<br/>DependencyInjection"]
    Tray --> Core
    Syntax --> Core
    Gallery --> Core
    Gallery --> DI
    Gallery --> Tray
    Gallery --> Syntax
    Gallery --> Toast

    style Abstractions fill:#e1f5ff,stroke:#0277bd
    style Core fill:#fff4e1,stroke:#f57f17
    style DI fill:#e8f5e9,stroke:#2e7d32
    style Tray fill:#e8f5e9,stroke:#2e7d32
    style Syntax fill:#e8f5e9,stroke:#2e7d32
    style Toast fill:#fff9c4,stroke:#f9a825
    style Gallery fill:#fce4ec,stroke:#c62828
    style FlaUI fill:#f3e5f5,stroke:#6a1b9a
    style FontMapper fill:#f3e5f5,stroke:#6a1b9a
    style Extension fill:#f3e5f5,stroke:#6a1b9a
    style ExtDI fill:#e0e0e0,stroke:#616161

Dependency rules:

Package Direct dependencies
Wpf.Ui.Abstractions None (zero external dependencies)
Wpf.Ui Wpf.Ui.Abstractions, Microsoft.Windows.CsWin32 (build-time), System.Memory
Wpf.Ui.DependencyInjection Wpf.Ui.Abstractions, Microsoft.Extensions.DependencyInjection.Abstractions 3.1.0
Wpf.Ui.Tray Wpf.Ui, System.Drawing.Common
Wpf.Ui.SyntaxHighlight Wpf.Ui
Wpf.Ui.ToastNotifications None (standalone stub)
Wpf.Ui.Gallery Wpf.Ui, Wpf.Ui.DependencyInjection, Wpf.Ui.Tray, Wpf.Ui.SyntaxHighlight, Wpf.Ui.ToastNotifications, CommunityToolkit.Mvvm, Microsoft.Extensions.Hosting
Wpf.Ui.FlaUI FlaUI.Core
Wpf.Ui.FontMapper None
Wpf.Ui.Extension VSIX SDK (VS 2022), template projects (Blank, Compact, Fluent)

2. Core Library Internal Structure (Layer Diagram)

The src/Wpf.Ui/ project is organized into six logical layers, from user-facing controls down to Win32 primitives.

graph TB
    subgraph "Layer 1 - Controls (77 control folders)"
        direction LR
        C1["FluentWindow"]
        C2["NavigationView"]
        C3["TitleBar"]
        C4["ContentDialog"]
        C5["NumberBox"]
        C6["AutoSuggestBox"]
        C7["ToggleSwitch"]
        C8["Snackbar"]
        C9["...70 more"]
    end

    subgraph "Layer 2 - Appearance / Theming"
        direction LR
        T1["ApplicationThemeManager<br/>(static)"]
        T2["ApplicationAccentColorManager<br/>(static)"]
        T3["SystemThemeWatcher<br/>(static)"]
        T4["WindowBackgroundManager<br/>(static)"]
        T5["ResourceDictionaryManager<br/>(internal)"]
    end

    subgraph "Layer 3 - Services"
        direction LR
        S1["NavigationService"]
        S2["ContentDialogService"]
        S3["SnackbarService"]
        S4["ThemeService"]
        S5["TaskBarService"]
    end

    subgraph "Layer 4 - Infrastructure"
        direction LR
        I1["Converters/<br/>18 IValueConverters"]
        I2["Extensions/<br/>14 extension classes"]
        I3["Markup/<br/>ControlsDictionary,<br/>ThemesDictionary,<br/>SymbolIconExtension,<br/>FontIconExtension"]
        I4["Animations/<br/>TransitionAnimationProvider"]
        I5["Input/<br/>IRelayCommand,<br/>RelayCommand&lt;T&gt;"]
        I6["Hardware/<br/>DPI, rendering tier"]
        I7["AutomationPeers/<br/>Accessibility"]
    end

    subgraph "Layer 5 - Win32 Interop"
        direction LR
        W1["CsWin32<br/>(NativeMethods.txt<br/>-> Windows.Win32)"]
        W2["Interop/<br/>UnsafeNativeMethods.cs<br/>PInvoke.cs"]
        W3["Win32/<br/>Utilities.cs<br/>OS version detection"]
    end

    subgraph "Layer 6 - Resources"
        direction LR
        R1["Theme/<br/>Light.xaml, Dark.xaml,<br/>HC1, HC2, HCBlack,<br/>HCWhite"]
        R2["Fonts/<br/>FluentSystemIcons-Filled.ttf<br/>FluentSystemIcons-Regular.ttf"]
        R3["Root resources:<br/>Accent.xaml, Palette.xaml,<br/>StaticColors.xaml,<br/>Typography.xaml,<br/>Variables.xaml"]
        R4["Wpf.Ui.xaml<br/>(master dictionary,<br/>merges all 77 control styles)"]
    end

    C1 & C2 & C3 & C4 & C5 & C6 & C7 & C8 --> T1 & T2
    C1 & C2 & C3 --> W2
    T1 & T2 & T3 & T4 --> T5
    T3 --> W2
    T4 --> W2
    S1 --> C2
    S2 --> C4
    S3 --> C8
    S5 --> W2
    I4 --> I6
    W2 --> W1
    W2 --> W3
    T5 --> R1

    style C1 fill:#fff4e1,stroke:#f57f17
    style C2 fill:#fff4e1,stroke:#f57f17
    style C3 fill:#fff4e1,stroke:#f57f17
    style C4 fill:#fff4e1,stroke:#f57f17
    style C5 fill:#fff4e1,stroke:#f57f17
    style C6 fill:#fff4e1,stroke:#f57f17
    style C7 fill:#fff4e1,stroke:#f57f17
    style C8 fill:#fff4e1,stroke:#f57f17
    style C9 fill:#fff4e1,stroke:#f57f17
    style T1 fill:#e8f5e9,stroke:#2e7d32
    style T2 fill:#e8f5e9,stroke:#2e7d32
    style T3 fill:#e8f5e9,stroke:#2e7d32
    style T4 fill:#e8f5e9,stroke:#2e7d32
    style T5 fill:#e8f5e9,stroke:#2e7d32
    style S1 fill:#e1f5ff,stroke:#0277bd
    style S2 fill:#e1f5ff,stroke:#0277bd
    style S3 fill:#e1f5ff,stroke:#0277bd
    style S4 fill:#e1f5ff,stroke:#0277bd
    style S5 fill:#e1f5ff,stroke:#0277bd
    style W1 fill:#ffebee,stroke:#c62828
    style W2 fill:#ffebee,stroke:#c62828
    style W3 fill:#ffebee,stroke:#c62828
    style R1 fill:#f3e5f5,stroke:#6a1b9a
    style R2 fill:#f3e5f5,stroke:#6a1b9a
    style R3 fill:#f3e5f5,stroke:#6a1b9a
    style R4 fill:#f3e5f5,stroke:#6a1b9a

Layer Details

Layer 1 -- Controls (77 control folders)

Each control follows a folder-per-control pattern: Controls/{Name}/{Name}.cs + Controls/{Name}/{Name}.xaml.

Controls extend WPF base classes (ContentControl, Control, Button, ToggleButton, Window, etc.) and optionally implement WPF UI interfaces: IAppearanceControl (accent/appearance support), IIconControl (icon support), IThemeControl (theme awareness), IDpiAwareControl (DPI awareness).

Complex controls are split into partial classes by concern. For example, NavigationView spans six partial files:

File Responsibility
NavigationView.Base.cs Core logic, constructor, static constructor
NavigationView.Properties.cs DependencyProperty registrations
NavigationView.Events.cs RoutedEvent registrations
NavigationView.Navigation.cs Page navigation logic
NavigationView.TemplateParts.cs Template part bindings (OnApplyTemplate)
NavigationView.AttachedProperties.cs Attached property definitions

Key controls: FluentWindow, NavigationView, TitleBar, ContentDialog, NumberBox, AutoSuggestBox, ToggleSwitch, Snackbar, BreadcrumbBar, InfoBar, RatingControl, ProgressRing.

Layer 2 -- Appearance/Theming

Class Pattern Responsibility
ApplicationThemeManager Static Runtime theme switching via ResourceDictionary swap. Fires ThemeChangedEvent.
ApplicationAccentColorManager Static Updates 20+ dynamic color resources (SystemAccentColor, AccentFillColorDefault, etc.) from WinRT UISettings or registry fallback.
SystemThemeWatcher Static Hooks WndProc for WM_THEMECHANGED, WM_DWMCOLORIZATIONCOLORCHANGED, WM_SYSCOLORCHANGE. Auto-syncs app theme with OS.
WindowBackgroundManager Static Applies DWM backdrop effects (Mica, Acrylic, Tabbed) via DwmSetWindowAttribute.
ResourceDictionaryManager Internal URI-based dictionary search and swap within Application.Resources.MergedDictionaries.

Six theme files: Light.xaml, Dark.xaml, HC1.xaml, HC2.xaml, HCBlack.xaml, HCWhite.xaml.

Layer 3 -- Services

Service implementations are defined at the src/Wpf.Ui/ root level alongside their interface files.

Service Interface Wraps
NavigationService INavigationService INavigationView control
ContentDialogService IContentDialogService ContentDialog control
SnackbarService ISnackbarService Snackbar control
ThemeService IThemeService ApplicationThemeManager static class
TaskBarService ITaskBarService COM ITaskbarList4 via Win32 interop

Layer 4 -- Infrastructure

Component Contents
Converters/ 18 IValueConverter implementations: BoolToVisibilityConverter, BrushToColorConverter, EnumToBoolConverter, IconSourceElementConverter, CornerRadiusSplitConverter, ProgressThicknessConverter, etc.
Extensions/ 14 extension method classes: ColorExtensions, FrameExtensions, NavigationServiceExtensions, SnackbarServiceExtensions, SymbolExtensions, UiElementExtensions, etc.
Markup/ XAML markup extensions: ControlsDictionary, ThemesDictionary, SymbolIconExtension, FontIconExtension, ImageIconExtension, ThemeResourceExtension, Design.
Animations/ TransitionAnimationProvider (applies FadeIn, SlideBottom, SlideRight, etc.), Transition enum, AnimationProperties. Checks HardwareAcceleration.RenderingTier before animating.
Input/ IRelayCommand, IRelayCommand<T>, RelayCommand<T> -- lightweight command implementations.
Hardware/ DpiHelper, DisplayDpi, HardwareAcceleration, RenderingTier -- DPI detection and rendering tier evaluation.
AutomationPeers/ CardControlAutomationPeer, ContentDialogAutomationPeer. Controls with automation peers override OnCreateAutomationPeer().
Taskbar/ TaskbarProgress, TaskbarProgressState -- Windows taskbar progress bar manipulation.

Layer 5 -- Win32 Interop

A three-layer architecture for native Windows API access:

  1. CsWin32 auto-generation (NativeMethods.txt lists 35 Win32 functions/types). The Microsoft.Windows.CsWin32 source generator produces P/Invoke signatures in the Windows.Win32 namespace. Covers DWM (DwmSetWindowAttribute, DwmIsCompositionEnabled), User32 (SetWindowLong, GetDpiForWindow, GetForegroundWindow), Shell32 (ITaskbarList4), and associated structs/enums.

  2. Managed wrappers (Interop/):

    • UnsafeNativeMethods.cs -- safe wrappers with handle validation (IntPtr.Zero check + PInvoke.IsWindow) before calling CsWin32-generated methods. Methods like ApplyWindowCornerPreference, ApplyBorderColor, RemoveWindowTitlebarContents.
    • PInvoke.cs -- manual [DllImport] for SetWindowLongPtr (not generated by CsWin32 for all overloads).
    • UnsafeReflection.cs -- type casting helpers for enum-to-Win32-struct conversion.
  3. OS utilities (Win32/):

    • Utilities.cs -- OS version detection (Vista, Windows 7, 8, 10, 11 build checks), DWM composition availability, system theme detection via IUISettings3 COM interface.

Layer 6 -- Resources

Path Contents
Resources/Theme/ 6 XAML theme dictionaries (Light, Dark, HC1, HC2, HCBlack, HCWhite)
Resources/Fonts/ FluentSystemIcons-Filled.ttf, FluentSystemIcons-Regular.ttf (embedded resources)
Resources/Accent.xaml Dynamic accent color resources
Resources/Palette.xaml Fluent Design color palette
Resources/StaticColors.xaml Non-theme-dependent color constants
Resources/Typography.xaml Font family, size, and weight resources
Resources/Variables.xaml Corner radius, spacing, sizing tokens
Resources/Wpf.Ui.xaml Master ResourceDictionary that merges all 77+ control style dictionaries
Resources/DefaultContextMenu.xaml Styled context menu for TextBox-like controls
Resources/DefaultFocusVisualStyle.xaml Fluent focus visual style

3. Control Architecture Pattern

The following class diagram shows how WPF UI controls extend WPF base classes, implement marker interfaces, and register DependencyProperties.

classDiagram
    direction TB

    namespace System.Windows.Controls {
        class WpfControl["Control"]
        class WpfContentControl["ContentControl"]
        class WpfButton["Button"]
        class WpfToggleButton["ToggleButton"]
        class WpfWindow["Window"]
    }

    namespace Wpf.Ui.Controls {
        class IAppearanceControl {
            <<interface>>
            +ControlAppearance Appearance
        }
        class IIconControl {
            <<interface>>
            +IconElement? Icon
        }
        class IThemeControl {
            <<interface>>
            +ApplicationTheme ApplicationTheme
        }
        class IDpiAwareControl {
            <<interface>>
            +DisplayDpi CurrentWindowDisplayDpi
        }

        class Button {
            +DependencyProperty IconProperty$
            +DependencyProperty AppearanceProperty$
            +DependencyProperty MouseOverBackgroundProperty$
            +DependencyProperty PressedBackgroundProperty$
            +DependencyProperty CornerRadiusProperty$
            +IconElement? Icon
            +ControlAppearance Appearance
            +CornerRadius CornerRadius
        }

        class FluentWindow {
            +DependencyProperty WindowCornerPreferenceProperty$
            +DependencyProperty WindowBackdropTypeProperty$
            +DependencyProperty ExtendsContentIntoTitleBarProperty$
            +WindowCornerPreference WindowCornerPreference
            +WindowBackdropType WindowBackdropType
            +bool ExtendsContentIntoTitleBar
            -static FluentWindow() DefaultStyleKeyProperty.OverrideMetadata()
        }

        class ToggleSwitch {
            +DependencyProperty OffContentProperty$
            +DependencyProperty OnContentProperty$
            +object? OffContent
            +object? OnContent
            -static ToggleSwitch() DefaultStyleKeyProperty.OverrideMetadata()
        }

        class NavigationView {
            <<partial>>
            .Base.cs: Core logic
            .Properties.cs: DependencyProperty defs
            .Events.cs: RoutedEvent defs
            .Navigation.cs: Page navigation
            .TemplateParts.cs: Template bindings
            .AttachedProperties.cs: Attached props
        }

        class ContentDialog {
            +ShowAsync() Task~ContentDialogResult~
            +Hide() void
        }
    }

    WpfButton <|-- Button
    WpfWindow <|-- FluentWindow
    WpfToggleButton <|-- ToggleSwitch
    WpfControl <|-- NavigationView
    WpfContentControl <|-- ContentDialog

    Button ..|> IAppearanceControl
    Button ..|> IIconControl

Control Authoring Recipe

Every WPF UI control follows a consistent authoring pattern:

1. C# class file (Controls/{Name}/{Name}.cs):

// All controls use the flat namespace Wpf.Ui.Controls
// regardless of their folder location (ReSharper CheckNamespace suppressed)
namespace Wpf.Ui.Controls;

public class MyControl : System.Windows.Controls.ContentControl, IAppearanceControl, IIconControl
{
    // DependencyProperty registration via static readonly fields
    public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
        nameof(Icon), typeof(IconElement), typeof(MyControl),
        new PropertyMetadata(null, null, IconElement.Coerce));

    // CLR property wrapper with [Bindable] and [Category] attributes
    [Bindable(true)]
    [Category("Appearance")]
    public IconElement? Icon
    {
        get => (IconElement?)GetValue(IconProperty);
        set => SetValue(IconProperty, value);
    }

    // Static constructor: override DefaultStyleKey for implicit style resolution
    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(MyControl),
            new FrameworkPropertyMetadata(typeof(MyControl)));
    }
}

2. XAML style file (Controls/{Name}/{Name}.xaml):

<ResourceDictionary ...>
    <Style TargetType="{x:Type controls:MyControl}">
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
        <!-- DynamicResource for all theme-dependent brushes -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:MyControl}">
                    <!-- Template definition -->
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

3. Registration in master dictionary (Resources/Wpf.Ui.xaml):

<ResourceDictionary.MergedDictionaries>
    <!-- ...other controls... -->
    <ResourceDictionary Source="pack://application:,,,/Wpf.Ui;component/Controls/MyControl/MyControl.xaml" />
</ResourceDictionary.MergedDictionaries>

Key invariants:

  • OverridesDefaultStyle="True" and SnapsToDevicePixels="True" are set on every control style.
  • Theme-dependent brushes always use DynamicResource (not StaticResource) so they update when themes switch at runtime.
  • The static constructor calling DefaultStyleKeyProperty.OverrideMetadata ensures WPF resolves the implicit style from the control's assembly rather than the application.
  • Complex controls split into partial classes by concern (properties, events, navigation logic, template parts).

4. Key Cross-Cutting Patterns

Flat Namespace

All controls reside in the single namespace Wpf.Ui.Controls despite being organized into individual subfolders under Controls/. This is enforced via // ReSharper disable once CheckNamespace pragmas in each file. The project does not suppress IDE0130 (namespace does not match folder structure) at the project level; instead, the ReSharper-specific pragma handles it.

Rationale: Consumers use a single xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" namespace in XAML. A flat C# namespace mirrors the flat XAML namespace.

Static Singleton Managers for Theming

The four core theming classes (ApplicationThemeManager, ApplicationAccentColorManager, SystemThemeWatcher, WindowBackgroundManager) are all static classes. They operate on Application.Current.Resources directly.

Trade-off: This sacrifices testability and multi-window isolation in favor of a simple, discoverable API. Consumers call ApplicationThemeManager.Apply(ApplicationTheme.Dark) without needing DI or service resolution. The ThemeService wraps these statics behind IThemeService for consumers who prefer DI.

The Gallery demo app and sample applications use CommunityToolkit.Mvvm source generators:

  • [ObservableProperty] for bindable properties
  • [RelayCommand] for ICommand implementations
  • ViewModels extend ObservableObject and implement INavigationAware
  • Pages implement INavigableView<TViewModel> for view-model association

This is a consumption pattern only; the core Wpf.Ui library has no dependency on CommunityToolkit.Mvvm.

Central Package Management

All NuGet package versions are declared in Directory.Packages.props at the repository root. Individual .csproj files reference packages without version numbers. This ensures consistent versions across all projects in the solution.

Service Interface Inversion

Service interfaces (INavigationService, IContentDialogService, etc.) are defined at the Wpf.Ui assembly root level, alongside their implementations. This allows:

  1. Direct instantiation for simple apps: var service = new NavigationService();
  2. DI registration for hosted apps: services.AddSingleton<INavigationService, NavigationService>();
  3. The ControlsServices.Initialize(IServiceProvider) static method enables control-level service resolution.

Async Dialog Pattern

ContentDialog.ShowAsync() returns Task<ContentDialogResult> using TaskCompletionSource to bridge the WPF event model to async/await. Supports CancellationToken and closing cancellation via ContentDialogClosingEventArgs.Cancel = true.

Win32 Interop Layering

Native Windows API calls follow a strict three-layer pipeline:

NativeMethods.txt  -->  CsWin32 source generator  -->  Windows.Win32 namespace (auto-generated)
                                                              |
                                                    Interop/UnsafeNativeMethods.cs (handle validation)
                                                              |
                                                    Win32/Utilities.cs (OS version guards)

Manual [DllImport] in Interop/PInvoke.cs supplements CsWin32 for signatures it cannot generate (e.g., SetWindowLongPtr with nint parameters).


5. Target Framework Matrix

gantt
    title Target Framework Coverage by Module
    dateFormat X
    axisFormat %s

    section Wpf.Ui.Abstractions
    netstandard2.0   :a1, 0, 1
    netstandard2.1   :a2, 1, 2
    net462           :a3, 2, 3
    net8.0           :a4, 3, 4
    net9.0           :a5, 4, 5
    net10.0          :a6, 5, 6

    section Wpf.Ui
    net462           :b1, 0, 1
    net472           :b2, 1, 2
    net481           :b3, 2, 3
    net8.0-windows   :b4, 3, 4
    net9.0-windows   :b5, 4, 5
    net10.0-windows  :b6, 5, 6

    section Wpf.Ui.DependencyInjection
    netstandard2.0   :c1, 0, 1
    netstandard2.1   :c2, 1, 2
    net462           :c3, 2, 3
    net8.0           :c4, 3, 4
    net9.0           :c5, 4, 5
    net10.0          :c6, 5, 6

    section Wpf.Ui.Tray
    net462           :d1, 0, 1
    net472           :d2, 1, 2
    net481           :d3, 2, 3
    net8.0-windows   :d4, 3, 4
    net9.0-windows   :d5, 4, 5
    net10.0-windows  :d6, 5, 6

    section Wpf.Ui.Gallery
    net10.0-windows10.0.26100.0 :e1, 5, 6
Module Target Frameworks Windows TFM Rationale
Wpf.Ui.Abstractions netstandard2.0, netstandard2.1, net462, net8.0, net9.0, net10.0 No Maximum compatibility; no WPF or Windows dependency. Consumable by any .NET project.
Wpf.Ui net10.0-windows, net9.0-windows, net8.0-windows, net481, net472, net462 Yes Requires WPF (<UseWPF>true</UseWPF>) and Win32 P/Invoke. Supports .NET Framework 4.6.2+ for legacy app modernization.
Wpf.Ui.DependencyInjection netstandard2.0, netstandard2.1, net462, net8.0, net9.0, net10.0 No Only depends on abstractions and MS DI interfaces. No WPF dependency.
Wpf.Ui.Tray net10.0-windows, net9.0-windows, net8.0-windows, net481, net472, net462 Yes Requires WPF + Win32 Shell32 interop for tray icons.
Wpf.Ui.SyntaxHighlight net10.0-windows, net9.0-windows, net8.0-windows, net481, net472, net462 Yes Requires WPF for custom control rendering.
Wpf.Ui.ToastNotifications net10.0-windows, net9.0-windows, net8.0-windows, net481, net472, net462 Yes Same targeting as core library (currently stub).
Wpf.Ui.FlaUI net10.0-windows, net9.0-windows, net8.0-windows, net481 Yes Test automation; constrained by FlaUI.Core compatibility.
Wpf.Ui.FontMapper net10.0 No Console build tool; targets latest runtime only.
Wpf.Ui.Gallery net10.0-windows10.0.26100.0 Yes Demo app targets latest .NET + latest Windows SDK for full feature demonstration.
Wpf.Ui.Extension net481 (via VSIX SDK) N/A VS 2022 VSIX extension; targets .NET Framework 4.8.1 per VSIX SDK requirements.

6. Service Registration & DI Integration

The following sequence diagram shows how WPF UI integrates with Microsoft.Extensions.DependencyInjection via the Generic Host pattern used in the Gallery and sample applications.

sequenceDiagram
    participant App as Application Startup
    participant Host as IHostBuilder
    participant SC as IServiceCollection
    participant Ext as ServiceCollectionExtensions
    participant SP as IServiceProvider
    participant CS as ControlsServices
    participant NavView as NavigationView
    participant Provider as INavigationViewPageProvider

    App->>Host: Host.CreateDefaultBuilder()
    App->>Host: ConfigureServices(services => ...)

    Host->>SC: services.AddSingleton<INavigationService, NavigationService>()
    Host->>SC: services.AddSingleton<IContentDialogService, ContentDialogService>()
    Host->>SC: services.AddSingleton<ISnackbarService, SnackbarService>()
    Host->>Ext: services.AddNavigationViewPageProvider<DI_PageProvider>()
    Ext->>SC: Register INavigationViewPageProvider

    Host->>SC: services.AddTransient<DashboardPage>()
    Host->>SC: services.AddTransient<SettingsPage>()

    App->>Host: Build()
    Host->>SP: Create IServiceProvider

    App->>CS: ControlsServices.Initialize(serviceProvider)
    CS->>CS: Store IServiceProvider for control-level resolution

    Note over NavView,Provider: At runtime, when NavigationView needs a page:
    NavView->>Provider: GetPage(typeof(DashboardPage))
    Provider->>SP: GetRequiredService(typeof(DashboardPage))
    SP-->>Provider: DashboardPage instance
    Provider-->>NavView: Resolved page

7. Control Lifecycle

WPF UI controls follow the standard WPF element lifecycle with additional steps for Fluent Design theming and Win32 interop integration.

stateDiagram-v2
    [*] --> Constructed: new MyControl()
    Constructed --> Constructed: Static ctor: DefaultStyleKeyProperty.OverrideMetadata()

    Constructed --> Loaded: Added to visual tree
    Loaded --> TemplateApplied: OnApplyTemplate()
    TemplateApplied --> TemplateApplied: GetTemplateChild() binds named parts

    TemplateApplied --> Themed: DynamicResource brushes resolved
    Themed --> Themed: ApplicationThemeManager.Changed → re-resolve brushes

    Themed --> Unloaded: Removed from visual tree
    Unloaded --> Loaded: Re-added to visual tree

    Unloaded --> GarbageCollected: No references remain
    GarbageCollected --> [*]

    note right of Constructed
        DependencyProperties registered
        via static readonly fields
    end note

    note right of TemplateApplied
        Controls bind template parts
        (e.g., PART_CloseButton)
        and hook event handlers
    end note

    note right of Themed
        Theme changes trigger
        DynamicResource updates
        without re-creating controls
    end note

Lifecycle Details

Phase Trigger WPF UI Actions
Constructed new / XAML parser Static constructor registers DefaultStyleKey; DependencyProperties are static
Loaded Added to visual tree Control subscribes to theme events if needed
Template Applied OnApplyTemplate() Named template parts (PART_*) resolved via GetTemplateChild()
Themed Resource resolution DynamicResource brushes resolve from current theme dictionary
Unloaded Removed from tree Event handlers and hooks should be cleaned up
GC No remaining references Standard .NET garbage collection

Conditional Compilation

The codebase uses #if directives to handle API differences across target frameworks:

Directive Usage
NET5_0_OR_GREATER Environment.OSVersion.Version vs. registry-based fallback for OS detection
NET6_0_OR_GREATER DisposeAsync for CancellationTokenRegistration
NET48_OR_GREATER or NETCOREAPP3_0_OR_GREATER IServiceProvider support in controls
NET8_0_OR_GREATER Newer framework API usage

PolySharp provides polyfills (e.g., IsExternalInit, CallerArgumentExpression, nullable attributes) so that C# 14 language features can be used across all target frameworks.