Status
Product name is MVVMExpress (Avalonia family). Package prefix is Plugin.Avalonia.MVVMExpress. Core does not reference Avalonia or Microsoft.Maui.Controls. Manual INotifyPropertyChanged and hand-written commands are first-class. There is no Shell host — put a Plugin.Avalonia.MVVMExpress.Controls.Frame named NavigationHost in the window.
License
Avalonia MVVMExpress is MIT licensed. There is no community-versus-commercial split and no revenue threshold. You may use the packages in commercial apps without a paid framework license. The SPDX identifier is MIT; LICENSE lives at the repository root and is packed with each nupkg.
That is a product choice, not a jab at other frameworks. If you already pay for a commercial MVVM stack, keep it. This family exists so a Avalonia team can take ViewModels, async state, and Frame navigation without a second license conversation — and so a MAUI team already on Plugin.Maui.MVVMExpress can keep the same Core contract on Avalonia.
Why this exists
A production Avalonia app needs more than INotifyPropertyChanged and ICommand: ViewModel lifecycle bound to Loaded / Unloaded, async work with cancellation, timeout, retry, and busy state, strongly typed Frame navigation, UI state richer than a boolean IsBusy, and testable ViewModels with no static dialog or Frame calls.
- CommunityToolkit.Mvvm covers properties, commands, and messaging.
- Prism covers region and URI navigation. It is a different composition model.
- ReactiveUI covers observable pipelines and activation, and requires System.Reactive.
None of those, alone, is a Avalonia-first operation + state + Frame-journal framework with the same Core contract as the MAUI family. MVVMExpress is that shell. It is not a fork of those libraries and it is not a MAUI or WPF package wearing a Avalonia TFM.
Design principles
- Core is UI-framework-free. Plugin.Avalonia.MVVMExpress.Core must not reference Avalonia or Microsoft.Maui.Controls.
- Optional means optional. Navigation, dialogs, validation, pagination, and testing are separate packages.
- Interfaces at the ViewModel boundary. ViewModels depend on INavigator, IDialogs, IMainThread — never on dialog or Frame statics.
- Async-first, cancellation-first. Every public async API accepts CancellationToken.
- No hidden global state. No static service locator in Core.
- One navigator per Window. IWindowContext / WindowNavigatorRegistry key navigation, dialogs, and scopes by window.
- No Shell. Frame + SectionHostViewModel cover stack navigation and in-place tabs.
- Do not silently swallow exceptions. Every catch transforms to Outcome, calls IErrorSink, logs and rethrows, or maps OperationCanceledException to Cancelled.
- No PackageReference to sibling MVVMExpress families. A ViewModel ports with a namespace swap, not a shared assembly.
How to read these docs
The left nav follows the surfaces a production Avalonia app actually touches. Start here for the contract. Getting started is the scaffold-or-install path, including dotnet new avalonia-mvvmexpress, the first screen, and the Playground clone. Project template documents the packed templates. IDE extensions covers the Visual Studio Code and Visual Studio Marketplace wrappers. Comparison evaluates CommunityToolkit.Mvvm, Prism.Avalonia, and ReactiveUI. Application model covers ViewModels, commands, DI, and messaging. Application shell covers Frame navigation, chat host, dialogs, validation, forms, and lists. Composition and internals explain packages, windows, the operation pipeline, tests, and scale. Release covers the shipped 1.0.0 roadmap and what waits for a later version.
- Shipped in 1.0.0 means types exist and tests exist. Frame navigation, dialogs, validation, pagination, templates, and IDE wrappers are complete.
- This is not Plugin.Maui.MVVMExpress or Plugin.Wpf.MVVMExpress. Do not add a PackageReference to those families. A ViewModel ports with a namespace swap.
- Source generators, Reactive, Shell, UseDeepLinks, and UseSecureSessionAuth are out of 1.0 — see the roadmap.
- Type names stay unique so CommunityToolkit.Mvvm or Prism can sit in the same app if you need them.
Naming — no collisions
Core type names must not collide with CommunityToolkit.Mvvm or Prism when both are referenced.
| Concept | MVVMExpress | Avoid copying |
|---|---|---|
| Observable base | ObservableModel | ObservableObject |
| ViewModel base | ViewModel / PageViewModel | Prism BindableBase / Screen |
| Sync command | ModelCommand | RelayCommand, DelegateCommand |
| Async command | AsyncModelCommand | AsyncRelayCommand, ReactiveCommand |
| Messenger | IMessageHub | IMessenger, IEventAggregator |
| Navigation | INavigator | INavigationService, IWindowManager |
| Dialogs | IDialogs | IDialogService, MessageBox.Show, ContentDialog statics |
| Parameters | typed records / IAcceptNavArgs<T> / IAcceptNavQuery | INavigationParameters |
| Result | Outcome / Outcome<T> | competing Result<T> packages |
Feature comparison
Designed product surface against CommunityToolkit.Mvvm, Prism.Avalonia, and ReactiveUI. This table does not claim MVVMExpress is faster than the others. Shipping versus designed is tracked in the repository API-PARITY.md.
| Feature | MVVMExpress | CommunityToolkit.Mvvm | Prism | ReactiveUI |
|---|---|---|---|---|
| Observable properties | Yes (hand-written in 1.0) | Yes | Yes | Yes |
| Commands / async commands | Yes | Yes | Yes / Partial | Yes |
| Source generators | Out of 1.0 | Yes | No | Yes |
| Navigation (Frame) | Yes (Frame replace-root, owned-window modal) | No | Yes (regions / URI) | Yes |
| Lifecycle + cancellation | Yes | No | Yes | Yes |
| Dialogs / toast | Yes (owned Window + overlay) | Separate | Yes | Extensions |
| Validation | Yes | Yes | Extensions | Yes |
| Reactive derived state | Out of 1.0 | No | No | Yes (Rx required) |
| Pagination + search | Yes | No | Extensions | Extensions |
| Unified AsyncState<T> | Yes | No | No | Extensions |
| Typed navigation record args | Yes | No | No (dictionary / URI) | Partial |
| Multi-window | Yes (IWindowContext per Window) | App-owned | Yes | Partial |
| Memory-leak GC tests | Yes (VM, command, pop, messenger) | Partial | Partial | Partial |
| Testing package | Yes | Partial | Yes | Yes |