更新客户端渲染,更新了壳
This commit is contained in:
@@ -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<T><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<T>"]
|
||||
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.
|
||||
Reference in New Issue
Block a user