View Models
Blazing.Mvvm provides base classes and conventions that let Blazor components work with ViewModels in a predictable MVVM style.
Available base classes
Use the base class that matches your ViewModel needs:
ViewModelBasederives fromObservableObjectRecipientViewModelBasederives fromObservableRecipientValidatorViewModelBasederives fromObservableValidator
Lifecycle methods
The ViewModel base classes mirror common ComponentBase lifecycle hooks:
OnInitializedOnInitializedAsyncOnParametersSetOnParametersSetAsyncOnAfterRenderOnAfterRenderAsyncShouldRender
This lets component lifecycle flow into the ViewModel without custom plumbing in every page.
Disposal behavior
Since v3.2.1, all ViewModel base classes implement IDisposable. When a ViewModel is disposed, it automatically unsubscribes from all IAsyncRelayCommand PropertyChanged events. This matters most for commands with AllowConcurrentExecutions set to false, where the framework monitors the command's IsRunning property to trigger UI updates. Without cleanup, those subscriptions leak.
Automatic disposal gives you:
- Memory leak prevention: command event subscriptions are cleaned up without manual tracking
- Simpler ViewModels: no need to track and unsubscribe from command events yourself
- A consistent pattern: all ViewModels follow the standard .NET dispose pattern
- Efficient garbage collection: commands and ViewModels are released promptly
If a derived ViewModel needs to release additional resources, override Dispose(bool disposing):
[ViewModelDefinition(Lifetime = ServiceLifetime.Scoped)]
public sealed partial class MyViewModel : ViewModelBase
{
private readonly CancellationTokenSource _cancellationTokenSource = new();
protected override void Dispose(bool disposing)
{
if (disposing)
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
}
base.Dispose(disposing);
}
}
Warning
If you previously implemented public void Dispose() yourself, change that to protected override void Dispose(bool disposing) so the base class can keep its cleanup behavior.
Service registration
ViewModels are registered as transient services by default. Use ViewModelDefinition to choose another lifetime:
[ViewModelDefinition(Lifetime = ServiceLifetime.Scoped)]
public partial class FetchDataViewModel : ViewModelBase
{
// ViewModel code
}
Then inherit your component from the matching MVVM base type:
@page "/fetchdata"
@inherits MvvmComponentBase<FetchDataViewModel>
Register with interfaces or abstract types
Use the generic ViewModelDefinition attribute when you want the ViewModel resolved through an abstraction:
[ViewModelDefinition<IFetchDataViewModel>]
public partial class FetchDataViewModel : ViewModelBase, IFetchDataViewModel
{
// ViewModel code
}
The component can then depend on that abstraction:
@page "/fetchdata"
@inherits MvvmComponentBase<IFetchDataViewModel>
Register keyed ViewModels
Use a key when you need explicit string-based lookup:
[ViewModelDefinition(Key = "FetchDataViewModel")]
public partial class FetchDataViewModel : ViewModelBase
{
// ViewModel code
}
Reference the key on the component with ViewModelKey:
@page "/fetchdata"
@attribute [ViewModelKey("FetchDataViewModel")]
@inherits MvvmComponentBase<FetchDataViewModel>
When to use each component base type
MvvmComponentBase<TViewModel>: default choice for most pages and componentsMvvmOwningComponentBase<TViewModel>: use when the component needs its own scoped dependency lifetimeMvvmLayoutComponentBase<TViewModel>: use when the layout itself owns a ViewModel