NuExt.Minimal.Mvvm.Wpf 0.7.3

Prefix Reserved
dotnet add package NuExt.Minimal.Mvvm.Wpf --version 0.7.3
                    
NuGet\Install-Package NuExt.Minimal.Mvvm.Wpf -Version 0.7.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NuExt.Minimal.Mvvm.Wpf" Version="0.7.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NuExt.Minimal.Mvvm.Wpf" Version="0.7.3" />
                    
Directory.Packages.props
<PackageReference Include="NuExt.Minimal.Mvvm.Wpf" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NuExt.Minimal.Mvvm.Wpf --version 0.7.3
                    
#r "nuget: NuExt.Minimal.Mvvm.Wpf, 0.7.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NuExt.Minimal.Mvvm.Wpf@0.7.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NuExt.Minimal.Mvvm.Wpf&version=0.7.3
                    
Install as a Cake Addin
#tool nuget:?package=NuExt.Minimal.Mvvm.Wpf&version=0.7.3
                    
Install as a Cake Tool

NuExt.Minimal.Mvvm.Wpf

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


Highlights

  • 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.


Key concepts

  • 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.

View location (predictable, overridable)

Views are resolved in a strict order by the window/document services: ViewTemplateViewTemplateKeyViewTemplateSelectorViewLocator.
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().

Windowed vs ViewWindowService

When to use which:

  • Use WindowedDocumentService when you manage multiple long‑lived windows as documents (ID reuse, ActiveDocument, bulk close).
  • Use ViewWindowService when you occasionally show a view as a window (modal/non‑modal) without keeping a document roster.

Quick Start (practical, minimal)

1) Async dialog with validation + automatic window placement

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.

2) Documents as windows (ID‑based reuse + per‑window behaviors)

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();
}

3) Parent–child helper (sticky parent binding)

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}"/>

4) Multi‑threaded WPF (per‑thread dispatcher, window‑oriented services)

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:


Installation

Via NuGet:

dotnet add package NuExt.Minimal.Mvvm.Wpf

Or via Visual Studio:

  1. Go to Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution....
  2. Search for NuExt.Minimal.Mvvm.Wpf.
  3. Click "Install".

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.

Contributing

Issues and PRs are welcome. Keep changes minimal and performance-conscious.

Acknowledgements

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.

License

MIT. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net9.0-windows7.0 is compatible.  net10.0-windows was computed.  net10.0-windows7.0 is compatible. 
.NET Framework net462 is compatible.  net463 was computed.  net47 was computed.  net471 is compatible.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

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

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.3 140 3/16/2026
0.7.0 106 2/13/2026