更新客户端渲染,更新了壳

This commit is contained in:
QWQLwToo
2026-07-06 23:05:40 +08:00
parent e7dd87bf7e
commit 31d778710b
1311 changed files with 172662 additions and 1582 deletions
@@ -0,0 +1,190 @@
# C4 Context Diagram (Level 1)
This document describes the system context of WPF UI -- the external actors, systems, and data flows that surround the library.
## Context Diagram
```plantuml
@startuml
!include <C4/C4_Context>
title System Context Diagram - WPF UI Library (v4.2.0)
Person(dev, "Library Consumer\n(WPF Developer)", "Develops WPF desktop applications\nusing WPF UI controls, theming,\nand navigation services")
Person(enduser, "End User", "Uses WPF desktop applications\nbuilt with WPF UI controls")
System(wpfui, "WPF UI Library", "Open-source WPF control library\nimplementing Microsoft Fluent Design.\n77+ controls, theming, Win32 interop,\nnavigation services.\n\nC# 14 / XAML\nNuGet: WPF-UI v4.2.0")
System_Ext(nuget, "NuGet.org", "Package registry.\nDistributes WPF-UI, WPF-UI.Abstractions,\nWPF-UI.DependencyInjection, WPF-UI.Tray\nNuGet packages")
System_Ext(vsmarket, "VS Marketplace", "Distributes Wpf.Ui.Extension VSIX\nwith project templates for\nVisual Studio 2022")
System_Ext(consumerapp, "Consumer WPF Application", "Desktop application built by the\nLibrary Consumer that references\nWPF UI NuGet packages and uses\nFluentWindow, NavigationView,\nthemed controls, etc.")
System_Ext(windows, "Windows OS", "Provides Win32 APIs:\n- DWM (Mica/Acrylic backdrops)\n- User32 (window management)\n- Shell32 (system tray, taskbar)\n- WinRT UISettings (accent colors)\n- System theme registry values")
System_Ext(github, "GitHub", "Source code hosting,\nGitHub Actions CI/CD,\nGitHub Pages documentation site")
System_Ext(fluenticons, "Fluent System Icons\n(Microsoft)", "Open-source icon font providing\nthousands of Regular and Filled\nglyph icons bundled as TTF fonts")
Rel(dev, wpfui, "References via NuGet,\nuses controls in XAML,\ncalls services in C#")
Rel(dev, nuget, "Installs packages\nvia dotnet add / NuGet UI")
Rel(dev, vsmarket, "Installs VS extension\nfor project templates")
Rel(dev, consumerapp, "Builds and maintains")
Rel(enduser, consumerapp, "Uses desktop\napplication")
Rel(wpfui, windows, "P/Invoke calls:\nDwmSetWindowAttribute,\nSetWindowLong,\nShell_NotifyIcon,\nIUISettings3 COM,\nWM_ message handling")
Rel(wpfui, fluenticons, "Bundles Regular + Filled\nTTF font files as\nembedded resources")
Rel_Back(nuget, wpfui, "Publishes packages\nvia GitHub Actions CD")
Rel_Back(github, wpfui, "Hosts source,\nruns CI/CD,\nhosts docs")
@enduml
```
## External Actors
### Library Consumers (WPF Developers)
The primary users of WPF UI are C#/WPF developers who want to apply Microsoft Fluent Design System styling to their desktop applications. They interact with the library by:
1. **Installing NuGet packages** -- `WPF-UI` (core), optionally `WPF-UI.DependencyInjection`, `WPF-UI.Tray`, `WPF-UI.Abstractions`
2. **Adding XAML resource dictionaries** -- `<ui:ControlsDictionary/>` and `<ui:ThemesDictionary Theme="Dark"/>` in `App.xaml`
3. **Using controls in XAML** -- Via the `xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"` namespace prefix
4. **Calling services in C#** -- `INavigationService`, `IContentDialogService`, `ISnackbarService`, `ApplicationThemeManager`
### End Users
End users interact with consumer WPF applications built using WPF UI. They experience Fluent Design visuals (rounded corners, Mica backdrop, accent colors) and interact with the 77+ controls. End users do not directly interact with the WPF UI library.
### Windows OS
WPF UI makes extensive use of the Windows platform through several channels:
| API Surface | Usage | Key Functions |
|---|---|---|
| **DWM (Desktop Window Manager)** | Backdrop effects (Mica, Acrylic, Tabbed), dark mode, window corner preferences | `DwmSetWindowAttribute`, `DwmIsCompositionEnabled` |
| **User32** | Window style manipulation, message pump interception, snap layouts | `SetWindowLong`, `GetWindowLong`, `SetWindowLongPtr` |
| **Shell32** | System tray icons, taskbar progress | `Shell_NotifyIcon`, `ITaskbarList4` COM |
| **WinRT UISettings** | System accent colors (8-color palette) | `IUISettings3` COM interface |
| **Registry** | Fallback for accent colors, OS version detection | `DWM\AccentColor`, `CurrentVersion` |
| **WndProc Messages** | Theme change detection, title bar hit testing | `WM_THEMECHANGED`, `WM_DWMCOLORIZATIONCOLORCHANGED`, `WM_NCHITTEST` |
### NuGet.org
The primary distribution channel for WPF UI. The GitHub Actions CD pipeline (`wpf-ui-cd-nuget.yaml`) publishes the following packages on every version bump (triggered by `Directory.Build.props` changes on the `main` branch):
| Package ID | Project | Description |
|---|---|---|
| `WPF-UI` | `Wpf.Ui` | Core library with controls, theming, services |
| `WPF-UI.Abstractions` | `Wpf.Ui.Abstractions` | Interface contracts for navigation |
| `WPF-UI.DependencyInjection` | `Wpf.Ui.DependencyInjection` | MS DI integration |
| `WPF-UI.Tray` | `Wpf.Ui.Tray` | System tray icon support |
### Visual Studio Marketplace
Distributes the `Wpf.Ui.Extension` VSIX for Visual Studio 2022 (x64 and arm64). Built by the `wpf-ui-cd-extension.yaml` workflow. Provides project templates for creating new WPF UI applications.
### GitHub
Hosts the source repository, runs CI/CD via GitHub Actions (7 workflows), and serves the DocFX documentation site via GitHub Pages.
## Data Flows
### NuGet Package Distribution
```mermaid
flowchart LR
Dev["Developer Machine"]
NuGet["NuGet.org"]
GH["GitHub Actions CD"]
GH -->|"nuget push *.nupkg<br/>Strong-name signed<br/>SourceLink embedded"| NuGet
NuGet -->|"dotnet add package WPF-UI<br/>Downloads .nupkg + .snupkg"| Dev
style Dev fill:#e1f5ff,stroke:#0277bd
style NuGet fill:#fff4e1,stroke:#f57f17
style GH fill:#e8f5e9,stroke:#2e7d32
```
### Win32 API Calls (Runtime)
```
Consumer WPF App
|
| Uses FluentWindow / TitleBar / SystemThemeWatcher
|
v
Wpf.Ui Core Library
|
|-- UnsafeNativeMethods (handle validation layer)
| |
| |-- CsWin32 PInvoke (source-generated declarations)
| |
| v
| Windows.Win32 namespace
|
v
Windows OS Kernel / DWM / Shell32 / User32
```
### XAML Resource Loading
```
Consumer App.xaml
|
| <ui:ThemesDictionary Theme="Dark"/>
| <ui:ControlsDictionary/>
|
v
ThemesDictionary (Markup Extension)
| Resolves pack URI:
| pack://application:,,,/Wpf.Ui;component/Resources/Theme/Dark.xaml
|
v
ControlsDictionary (Markup Extension)
| Resolves pack URI:
| pack://application:,,,/Wpf.Ui;component/Resources/Wpf.Ui.xaml
| --> Merges all 77 control .xaml ResourceDictionaries
| --> Loads font resources (FluentSystemIcons)
| --> Loads palette, typography, variables
|
v
WPF Resource System
| Controls resolve styles via DefaultStyleKeyProperty
| Theme brushes resolved via DynamicResource
| Accent colors updated programmatically by ApplicationAccentColorManager
```
### Theme Change Flow
```
Windows OS
|
| WM_DWMCOLORIZATIONCOLORCHANGED
| WM_THEMECHANGED
| WM_SYSCOLORCHANGE
|
v
SystemThemeWatcher (HwndSource.AddHook)
|
| Detects OS theme change
|
v
ApplicationThemeManager.ApplySystemTheme()
|
|-- ResourceDictionaryManager.UpdateDictionary("theme", newThemeUri)
| Swaps Light.xaml <-> Dark.xaml in MergedDictionaries
|
|-- ApplicationAccentColorManager.Apply(accentColor, theme)
| Updates 20+ dynamic color resources
|
|-- WindowBackgroundManager.UpdateBackground(window)
| Applies DWM dark mode attribute + backdrop effect
|
|-- Fires ApplicationThemeManager.Changed event
| --> Subscribers (CodeBlock, InternalNotifyIconManager, consumer code)
```
@@ -0,0 +1,655 @@
# 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.
```mermaid
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.
```mermaid
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.
```mermaid
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`):
```csharp
// 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`):
```xml
<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`):
```xml
<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.
### CommunityToolkit.Mvvm in Gallery and Samples
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
```mermaid
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.
```mermaid
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.
```mermaid
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.