gbastecki.BlazorMvvm 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package gbastecki.BlazorMvvm --version 1.0.0
                    
NuGet\Install-Package gbastecki.BlazorMvvm -Version 1.0.0
                    
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="gbastecki.BlazorMvvm" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="gbastecki.BlazorMvvm" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="gbastecki.BlazorMvvm" />
                    
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 gbastecki.BlazorMvvm --version 1.0.0
                    
#r "nuget: gbastecki.BlazorMvvm, 1.0.0"
                    
#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 gbastecki.BlazorMvvm@1.0.0
                    
#: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=gbastecki.BlazorMvvm&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=gbastecki.BlazorMvvm&version=1.0.0
                    
Install as a Cake Tool

BlazorMvvm

https://github.com/github/docs/actions/workflows/main.yml

Use the MVVM pattern for Blazor with a simple and lightweight library.

Usage

ViewModel

View models have to inherit BlazorMvvm.BlazorViewModel.

Example HomeViewModel.cs:

using BlazorMvvm;
namespace YourNamespace;
public class HomeViewModel : BlazorViewModel
{
    private int _counter;
    public int Counter
    {
        get => _counter;
        set
        {
            if (_counter == value) return;
            _counter = value;
            base.OnPropertyChanged(); //this will trigger the UI refresh
        }
    }

    private int _counter2;
    public int Counter2
    {
        get => _counter2;
        set => Set(ref _counter2, value); //this will perform an equality check and if the property and value don't match it will raise OnPropertyChanged event
    }
}

ComponentBase

Components have to inherit BlazorMvvm.BlazorMvvmComponentBase.

When initializing a component, set the data context for the element when it participates in data binding using the SetDataContext method.

Example Home.razor:

@using BlazorMvvm
@inherits BlazorMvvmComponentBase<HomeViewModel>

Example Home.razor.cs:

using BlazorMvvm;
namespace YourNamespace;
public partial class Home : BlazorMvvmComponentBase<HomeViewModel>
{
    HomeViewModel ViewModel = new();

    protected override void OnInitialized()
    {
        SetDataContext(ViewModel);
        base.OnInitialized();
    }
}

ObservableComponent

You can control the rendering of specific parts of a component by implementing the ObservableComponent.

Example Home.razor:

@using BlazorMvvm
@inherits BlazorMvvmComponentBase<HomeViewModel>
<ObservableComponent ViewModel="ObservablePartViewModel">
    <div>ObservableComponent current counter: @ObservablePartViewModel.Counter</div>
</ObservableComponent>
<ObservableComponent ViewModel="SharedObservableViewModel" PropertyNames="[nameof(SharedObservableViewModel.Counter1)]">
    <div>SharedObservableViewModel current counter 1: @SharedObservableViewModel.Counter1</div>
</ObservableComponent>
<ObservableComponent ViewModel="SharedObservableViewModel" PropertyNames="[nameof(SharedObservableViewModel.Counter2), nameof(SharedObservableViewModel.Counter3)]">
    <div>SharedObservableViewModel current counter 2: @SharedObservableViewModel.Counter2</div>
    <div>SharedObservableViewModel current counter 3: @SharedObservableViewModel.Counter3</div>
</ObservableComponent>

Example Home.razor.cs:

using BlazorMvvm;
namespace YourNamespace;
public partial class Home : BlazorMvvmComponentBase<HomeViewModel>
{
    HomeViewModel ViewModel = new();
    ObservablePartViewModel ObservablePartViewModel = new();
    SharedObservableViewModel SharedObservableViewModel = new();
	
    protected override void OnInitialized()
    {
        SetDataContext(ViewModel);
        base.OnInitialized();
    }
}

Passing a ViewModel to an ObservableComponent automatically binds to it.

If you also pass PropertyNames, the component is refreshed only if the OnPropertyChanged event is invoked for the associated property names.

Based on the above example, modifying the SharedObservableViewModel.Counter3 property will refresh the fragment that contains the passed property names Counter2 and Counter3, but will not refresh the fragment that contains Counter1.

Commands

Command implementations can expose a method or delegate to the component.

Available commands:

//Parameterless commands
BlazorAsyncCommand(Func<Task> execute, Func<Task<bool>>? canExecute = null, bool allowConcurrentExecutions = false);
BlazorCommand(Action execute, Func<bool>? canExecute = null);

//Object type params commands
BlazorAsyncRelayCommand(Func<object[]?, Task> execute, Func<object[]?, Task<bool>>? canExecute = null, bool allowConcurrentExecutions = false);
BlazorRelayCommand(Action<object[]?> execute, Func<object[]?, bool>? canExecute = null);

//Generic type commands
BlazorAsyncRelayCommand<T>(Func<T, Task> execute, Func<T, Task<bool>>? canExecute = null, bool allowConcurrentExecutions = false);
BlazorRelayCommand<T>(Action<T> execute, Func<T, bool>? canExecute = null);

If canExecute is provided, it will be executed before execute, and if it returns false, it will prevent the execute delegate from invoking.

Asynchronous commands also expose an IsExecuting property, and if AllowConcurrentExecutions is set to false, it will prevent the same command from being executed multiple times.

You can also subscribe to the OnIsExecutingChanged event, which is raised when the IsExecuting property changes.

Example ButtonExampleViewModel.cs:

using BlazorMvvm;
namespace YourNamespace;
public class ButtonExampleViewModel : BlazorViewModel
{
    public readonly IBlazorAsyncCommand DisableButtonCommand;
    public ButtonExampleViewModel()
    {
        DisableButtonCommand = new BlazorAsyncCommand(DisableButton);
        DisableButtonCommand.OnIsExecutingChanged += DisableButtonCommand_OnIsExecutingChanged;
    }
    ~ButtonExampleViewModel()
    {
        DisableButtonCommand.OnIsExecutingChanged -= DisableButtonCommand_OnIsExecutingChanged;
    }
    private void DisableButtonCommand_OnIsExecutingChanged(bool isExecuting)
    {
        base.OnPropertyChanged();
    }

    private async Task DisableButton()
    {
        await Task.Delay(5000);
    }
}

Example .razor:

@using BlazorMvvm
@inherits BlazorMvvmComponentBase<HomeViewModel>

<ObservableComponent ViewModel="ButtonExampleViewModel">
    <button @onclick="ButtonExampleViewModel.DisableButtonCommand.Execute" disabled="@ButtonExampleViewModel.DisableButtonCommand.IsExecuting">Disable button for a few seconds</button>
</ObservableComponent>
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 1,233 12/25/2025
1.1.2 802 12/2/2025
1.1.1 703 12/1/2025
1.1.0 409 11/30/2025
1.0.3 254 11/22/2025
1.0.2 330 11/11/2025
1.0.1 247 10/30/2025
1.0.0 283 2/2/2025