Skip to content

Installation

Navius.Wpf ships as four packages. Three target net8.0-windows and net10.0-windows and declare an explicit package id and version; Navius.Wpf.Charts targets the same two frameworks but declares neither.

Package Version Project references Other dependencies
Navius.Wpf.Primitives 1.0.0-preview.1 none none
Navius.Wpf.Ui 1.0.0-preview.1 Navius.Wpf.Primitives none
Navius.Wpf.Motion 1.0.0-preview.1 none none
Navius.Wpf.Charts not pinned (see below) Navius.Wpf.Primitives LiveChartsCore.SkiaSharpView.WPF 2.0.5

The library ships as NuGet packages at 1.0.0-preview.1. Navius.Wpf.Charts’s csproj sets no PackageId or Version property, unlike the other three, so packing it falls back to the .NET SDK’s own defaults (the project name as the package id, 1.0.0 as the version) rather than the 1.0.0-preview.1 the other three declare explicitly.

Add whichever packages a project needs:

dotnet add package Navius.Wpf.Primitives --version 1.0.0-preview.1
dotnet add package Navius.Wpf.Ui --version 1.0.0-preview.1
dotnet add package Navius.Wpf.Motion --version 1.0.0-preview.1
dotnet add package Navius.Wpf.Charts

Navius.Wpf.Ui and Navius.Wpf.Charts both carry a project reference to Navius.Wpf.Primitives, so a project that only needs styled components or charts does not need to add Navius.Wpf.Primitives on its own; NuGet resolves it transitively.

Navius.Wpf also ships a copy-paste component registry, navius-wpf (package id navius-wpf, version 1.0.0-preview.1, packed with PackAsTool so it installs and runs as a dotnet tool). The registry lives at registry/registry.json in the source repo and is bundled into the tool package itself, alongside a copy of the Navius.Wpf.Primitives and Navius.Wpf.Ui source trees under registry-source/, so add and registry-sync still work when the tool is installed globally with no local repo checkout.

The command surface, as implemented in tools/Navius.Wpf.Cli/Program.cs:

navius-wpf list [--registry <path>]
navius-wpf add <name> --to <dir> --namespace <ns> [--root <repo>] [--registry <path>]
navius-wpf registry-sync [--root <repo>] [--registry <path>]
  • list prints every registry item’s name, type, file count, and registryDependencies.
  • add <name> is the vendoring command a consumer runs. --to <dir> and --namespace <ns> are required. --root <repo> points source-path resolution at a specific repo checkout instead of the current directory; --registry <path> points at a specific registry.json instead of the one resolved automatically (working-directory copy first, then the bundled copy next to the tool’s own assembly).
  • registry-sync regenerates registry/registry.json by rescanning src/Navius.Wpf.Primitives and src/Navius.Wpf.Ui. This is a maintainer command for the Navius.Wpf repo itself (the registry is generated, never hand-edited), not something a consuming project runs.

registry/schema.json constrains type to registry:core, registry:primitive, or registry:styled. In practice:

  • registry:core is a single item, named core: the shared overlay, positioning, and theming base layer (Overlays/, Positioning/, Theming/, Controls/Internal/, plus the OverlayBackdrop.xaml, Tokens.Light.xaml, and Tokens.Dark.xaml theme dictionaries).
  • registry:primitive items map to a Navius.Wpf.Primitives control family (one folder under Controls/, or a flat Tier-A file like NaviusButton).
  • registry:styled items map to a Navius.Wpf.Ui component.

Navius.Wpf.Charts is not in the registry: registry-sync explicitly notes it as “found but intentionally excluded” and does not register any registry:chart type (the schema does not define one). Charts is only consumable as a package or project reference, not through add.

Each item’s files array lists path (a repo-root-relative source path), type (registry:code or registry:theme), and target (the path under the consumer’s --to directory).

An item’s registryDependencies names other item ids its source references. add resolves this set transitively and topologically (dependencies copied before the item that needs them) before copying anything, so vendoring select also brings in anchored-popup and core, the exact composite case this closure step exists for: a registry item vendored without its full dependency closure left dangling types that did not compile, a defect class first found while hardening the sibling web CLI. tests/Navius.Wpf.Cli.Tests/VendoringClosureTests.cs is the gate: it shells the real add command against a temp WPF classlib project, then runs dotnet build on the result, for both a no-dependency item (button) and the select composite case.

Two text rewrites run on every copied file, in this order:

  1. Theme pack-URI fix: a XAML file with pack://application:,,,/Navius.Wpf.Primitives;component/Themes/X.xaml (or the shorthand /Navius.Wpf.Primitives;component/Themes/X.xaml) has that authority segment stripped to a bare X.xaml, since vendored source has no compiled assembly for the pack URI to resolve against; theme dictionaries land as plain files next to each other. The Navius.Wpf.Ui equivalent is rewritten to Ui.X.xaml instead, since Ui-origin and Primitives-origin theme dictionaries land in the same flattened NaviusWpf/Themes/ folder and would otherwise collide by name.
  2. Namespace rewrite: every occurrence of Navius.Wpf.Primitives in the file text becomes <namespace>.NaviusWpf.Primitives, and every occurrence of Navius.Wpf.Ui becomes <namespace>.NaviusWpf.Ui, where <namespace> is the --namespace value. This is a plain text replace, so it also rewrites xmlns:controls="clr-namespace:Navius.Wpf.Primitives.Controls" style strings inside XAML, not just C# namespace declarations.
navius-wpf add select --to . --namespace MyApp

select’s registryDependencies are ["anchored-popup", "core"], and anchored-popup itself depends on core, so the resolved, deps-first copy order is core, anchored-popup, select. With --to . and --namespace MyApp, the files land at:

NaviusWpf/Primitives/Controls/Internal/LogicalTreeWalker.cs (core)
NaviusWpf/Primitives/Controls/Internal/PanelHeightAnimator.cs (core)
NaviusWpf/Primitives/Controls/Internal/SegmentEngine.cs (core)
NaviusWpf/Primitives/Controls/Internal/TimePickerOptions.cs (core)
NaviusWpf/Primitives/Controls/Internal/VisualAncestorWalker.cs (core)
NaviusWpf/Primitives/Overlays/OverlayBackdrop.cs (core)
NaviusWpf/Primitives/Overlays/OverlayCloseReason.cs (core)
NaviusWpf/Primitives/Overlays/OverlayClosingEventArgs.cs (core)
NaviusWpf/Primitives/Overlays/OverlayDismissPolicy.cs (core)
NaviusWpf/Primitives/Overlays/OverlayOptions.cs (core)
NaviusWpf/Primitives/Overlays/OverlaySession.cs (core)
NaviusWpf/Primitives/Overlays/OverlayStack.cs (core)
NaviusWpf/Primitives/Positioning/AnchoredPlacementOptions.cs (core)
NaviusWpf/Primitives/Positioning/MonitorWorkArea.cs (core)
NaviusWpf/Primitives/Positioning/PlacementAlign.cs (core)
NaviusWpf/Primitives/Positioning/PlacementMath.cs (core)
NaviusWpf/Primitives/Positioning/PlacementResult.cs (core)
NaviusWpf/Primitives/Positioning/PlacementSide.cs (core)
NaviusWpf/Primitives/Theming/NaviusTheme.cs (core)
NaviusWpf/Primitives/Theming/ThemeManager.cs (core)
NaviusWpf/Themes/OverlayBackdrop.xaml (core)
NaviusWpf/Themes/Tokens.Dark.xaml (core)
NaviusWpf/Themes/Tokens.Light.xaml (core)
NaviusWpf/Primitives/Controls/NaviusAnchoredPopup.cs (anchored-popup)
NaviusWpf/Primitives/Controls/Select/NaviusSelect.cs (select)
NaviusWpf/Primitives/Controls/Select/NaviusSelectBase.cs (select)
NaviusWpf/Primitives/Controls/Select/NaviusSelectEventArgs.cs (select)
NaviusWpf/Primitives/Controls/Select/NaviusSelectItem.cs (select)
NaviusWpf/Primitives/Controls/Select/SelectSelectionEngine.cs (select)
NaviusWpf/Themes/Select.xaml (select)

Every .cs and .xaml file in that set has Navius.Wpf.Primitives rewritten to MyApp.NaviusWpf.Primitives (this closure has no Navius.Wpf.Ui-origin file, so no Ui.-prefixed theme file or Ui namespace rewrite occurs here).

The Gallery app (apps/Navius.Wpf.Gallery) shows the minimum wiring a consuming app needs, whether it references the packages or vendors via the CLI.

App.xaml declares an empty <Application.Resources>; it does not merge any control theme dictionary by hand. That works because both Navius.Wpf.Primitives and Navius.Wpf.Ui carry [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)], so WPF’s own default-style resolution locates each assembly’s Themes/Generic.xaml automatically; no explicit merge is needed for control templates and default styles.

The one thing that does need runtime wiring is the token dictionary, since controls read Navius.* tokens through DynamicResource, and a DynamicResource lookup needs that dictionary present somewhere in the live resource chain. App.xaml.cs supplies it in OnStartup:

using System.Windows;
using Navius.Wpf.Primitives.Theming;
namespace MyApp;
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
ThemeManager.Apply(NaviusTheme.Light);
}
}

ThemeManager.Apply(NaviusTheme.Light) injects Themes/Tokens.Light.xaml into Application.Current.Resources.MergedDictionaries, which is enough for every consumer of the tokens (package reference or vendored) to resolve DynamicResource Navius.* lookups. A vendored project calls the same method from its rewritten namespace (e.g. MyApp.NaviusWpf.Primitives.Theming.ThemeManager.Apply(...)), since the CLI’s namespace rewrite applies to the vendored ThemeManager.cs and NaviusTheme.cs exactly as it does to any other vendored file.