![]() |
VOOZH | about |
dotnet add package NuExt.Minimal.Mvvm.Wpf --version 0.7.3
NuGet\Install-Package NuExt.Minimal.Mvvm.Wpf -Version 0.7.3
<PackageReference Include="NuExt.Minimal.Mvvm.Wpf" Version="0.7.3" />
<PackageVersion Include="NuExt.Minimal.Mvvm.Wpf" Version="0.7.3" />Directory.Packages.props
<PackageReference Include="NuExt.Minimal.Mvvm.Wpf" />Project file
paket add NuExt.Minimal.Mvvm.Wpf --version 0.7.3
#r "nuget: NuExt.Minimal.Mvvm.Wpf, 0.7.3"
#:package NuExt.Minimal.Mvvm.Wpf@0.7.3
#addin nuget:?package=NuExt.Minimal.Mvvm.Wpf&version=0.7.3Install as a Cake Addin
#tool nuget:?package=NuExt.Minimal.Mvvm.Wpf&version=0.7.3Install as a Cake Tool
NuExt.Minimal.Mvvm.Wpf is a WPF add‑on for the lightweight MVVM core (NuExt.Minimal.Mvvm). It delivers deterministic async UX, predictable window and document services, parent–child view‑model patterns, and control/window‑oriented APIs—with minimal ceremony and zero heavy dependencies.
👁 NuGet
👁 Build
👁 License
👁 Downloads
Parent–child and control/window‑oriented VMs
ControlViewModel/WindowViewModel model the UI the way WPF actually runs it: parent–child relations, deterministic event‑to‑command bindings via attached behaviors, and dispatcher‑safe operations via IDispatcherService (each UI thread owns its own dispatcher).
Explicit view composition
Predictable view resolution with overridable conventions and a safe fallback view. Use templates when you have them, or a customizable ViewLocator when you don’t have one. See View location below for details.
Async‑first UX
Dialogs and documents are orchestrated with proper async lifecycle: view creation, VM initialization, cancellation, and clean completion—without UI deadlocks. IAsyncDialogService shows modal dialogs with typed commands/results and optional validation. IAsyncDocumentManagerService manages the creation/activation/closure of documents that live as windows or tabs.
Deterministic windows and documents
Restore/save window position/size/state (WindowPlacementService). Manage documents as windows (WindowedDocumentService) or as tabs (TabbedDocumentService) using a unified IAsyncDocument contract (ID, title, Show/Hide/CloseAsync, “dispose VM on close”, optional “hide instead of close”).
Multi‑threaded WPF ready
Works in multi‑UI‑thread apps (each window on its own dispatcher). DispatcherService is injected per thread; window‑oriented services are dispatcher‑aware by design.
Minimal deps, performance‑oriented
No heavy external frameworks. Hot paths avoid needless allocations, lifecycle is explicit, and services/events are carefully cleaned up.
Compatibility:
WPF on .NET 8/9/10 and .NET Framework 4.6.2+. Works with any MVVM stack and pairs naturally with NuExt.Minimal.Mvvm.
Control/Window‑oriented VMs + DispatcherService — VMs expose a predictable async lifecycle and run code on the owning UI thread via IDispatcherService. This is why the same patterns also work in multi‑threaded WPF, where each window has its own dispatcher.
IAsyncDocument + IAsyncDocumentManagerService — a document is a hosted view + VM with a stable contract (Id, Title, Show/Hide/CloseAsync, optional “dispose VM on close”). The manager creates documents (CreateDocumentAsync), tracks ActiveDocument, enumerates Documents, supports bulk CloseAllAsync, and plugs into WPF as windows (WindowedDocumentService) or tabs (TabbedDocumentService).
IAsyncDialogService — shows modal dialogs with a view resolved by name/template and a view‑model you provide; returns either a MessageBoxResult or a selected UICommand. The service handles view creation, optional title binding, validation (via IDataErrorInfo / INotifyDataErrorInfo), and clean teardown.
Views are resolved in a strict order by the window/document services:
ViewTemplate → ViewTemplateKey → ViewTemplateSelector → ViewLocator.
The default ViewLocator searches loaded assemblies, caches types, and produces a fallback view if nothing matches.
Register a custom view name (e.g., when you don’t follow naming conventions):
// if the default locator is the built-in ViewLocator, you can register names:
if (Minimal.Mvvm.Wpf.ViewLocator.Default is Minimal.Mvvm.Wpf.ViewLocator v)
{
v.RegisterType("MyCustomView", typeof(MyCustomView));
}
Fallback view
When no view is found (or view creation fails), a lightweight FallbackView is created with a readable error text. Override ViewLocatorBase or assign ViewLocator.Default if you need full control over lookup rules. If you need to alter caches or registrations during long‑running sessions, the built‑in locator also exposes ClearCache() and ClearRegisteredTypes().
When to use which:
WindowedDocumentService when you manage multiple long‑lived windows as documents (ID reuse, ActiveDocument, bulk close).ViewWindowService when you occasionally show a view as a window (modal/non‑modal) without keeping a document roster.XAML (attach services to your Window via behaviors):
<Window
...
xmlns:nx="http://schemas.nuext.minimal/xaml">
<nx:Interaction.Behaviors>
<nx:WindowService/>
<nx:InputDialogService
x:Name="Dialogs"
MessageBoxButtonLocalizer="{StaticResource MessageBoxButtonLocalizer}"
ValidatesOnDataErrors="True"
ValidatesOnNotifyDataErrors="True"/>
<nx:WindowPlacementService
FileName="MainWindow"
DirectoryName="{Binding EnvironmentService.SettingsDirectory, FallbackValue={x:Null}}"/>
</nx:Interaction.Behaviors>
</Window>
ViewModel (show a dialog with a view and a VM):
private IAsyncDialogService Dialogs => GetService<IAsyncDialogService>("Dialogs");
public async Task EditAsync(MyModel myModel, CancellationToken ct)
{
await using var vm = new EditViewModel();
var result = await Dialogs.ShowDialogAsync(
MessageBoxButton.OKCancel,
title: "Edit",
documentType: "EditView",
viewModel: vm,
parentViewModel: this,
parameter: myModel,
cancellationToken: ct);
if (result != MessageBoxResult.OK) return;
// proceed with the edited model
}
WindowPlacementService is fully automatic once attached: it restores on load and saves on close—no extra code needed.
XAML (window manager + per‑window template behaviors):
<nx:Interaction.Behaviors>
<nx:WindowedDocumentService x:Name="Windows"
ActiveDocument="{Binding ActiveWindow}"
FallbackViewType="{x:Type views:ErrorView}">
<nx:WindowedDocumentService.WindowStyle>
<Style TargetType="{x:Type Window}">
<Setter Property="nx:Interaction.BehaviorsTemplate">
<Setter.Value>
<DataTemplate>
<ItemsControl>
<nx:WindowService Name="CurrentWindowService"/>
<nx:EventToCommand EventName="ContentRendered"
Command="{Binding ContentRenderedCommand}"/>
</ItemsControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</nx:WindowedDocumentService.WindowStyle>
</nx:WindowedDocumentService>
</nx:Interaction.Behaviors>
ViewModel (find by ID or create; dispose VM on close):
public IAsyncDocumentManagerService WindowManager => GetService<IAsyncDocumentManagerService>("Windows");
public async Task OpenInWindowAsync(MyModel myModel, CancellationToken ct)
{
var doc = await WindowManager.FindDocumentByIdOrCreateAsync(
id: myModel.Id,
createDocumentCallback: async mgr =>
{
var vm = new MyModelViewModel();
try
{
var d = await mgr.CreateDocumentAsync(
documentType: "MyModelView",
viewModel: vm,
parentViewModel: this,
parameter: myModel,
cancellationToken: ct);
d.DisposeOnClose = true;
return d;
}
catch
{
await vm.DisposeAsync();
throw;
}
});
doc.Show();
}
Use ViewModelExtensions.ParentViewModel to set a parent VM on child view models directly in XAML; enable StickyParentBinding="True" to keep it in sync on every DataContext change.
<ContentPresenter
xmlns:nx="http://schemas.nuext.minimal/xaml"
nx:ViewModelExtensions.ParentViewModel="{Binding}"
nx:ViewModelExtensions.StickyParentBinding="True"
Content="{Binding ChildVm}"/>
Each UI thread has its own DispatcherService instance injected via behaviors; window‑oriented services (ViewWindowService / WindowedDocumentService) are dispatcher‑aware and safe to call on the owning thread.
See the runnable samples:
Via NuGet:
dotnet add package NuExt.Minimal.Mvvm.Wpf
Or via Visual Studio:
Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution....NuExt.Minimal.Mvvm.Wpf.Nice to have: NuExt.Minimal.Mvvm.SourceGenerator to remove boilerplate in view‑models. Also see NuExt.Minimal.Mvvm.MahApps.Metro - a NuGet package that provides extensions for integrating with MahApps.Metro.
Issues and PRs are welcome. Keep changes minimal and performance-conscious.
The DevExpress MVVM Framework has been a long‑time source of inspiration. NuExt.Minimal.Mvvm.Wpf distills similar ideas into a lightweight, async‑first, and explicit composition model tailored for contemporary WPF apps.
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 net8.0-windows7.0 is compatible. net9.0-windows net9.0-windows was computed. net9.0-windows7.0 net9.0-windows7.0 is compatible. net10.0-windows net10.0-windows was computed. net10.0-windows7.0 net10.0-windows7.0 is compatible. |
| .NET Framework | net462 net462 is compatible. net463 net463 was computed. net47 net47 was computed. net471 net471 is compatible. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
Showing the top 1 NuGet packages that depend on NuExt.Minimal.Mvvm.Wpf:
| Package | Downloads |
|---|---|
|
NuExt.Minimal.Mvvm.MahApps.Metro
Extensions for the MahApps.Metro toolkit using the Minimal MVVM Framework for streamlined Metro-style WPF app development. Commonly Used Types: Minimal.Mvvm.Wpf.DialogCoordinatorService Minimal.Mvvm.Wpf.MetroDialogService Minimal.Mvvm.Wpf.MetroTabbedDocumentService MahApps.Metro.Controls.Dialogs.MetroDialog |
This package is not used by any popular GitHub repositories.