DEV Community

Cover image for Using Blazor? Consider MVVM
Pavel Osadchuk
Pavel Osadchuk

Posted on

8 2

Using Blazor? Consider MVVM

With the first glance at Blazor - a framework for building interactive client-side web UI with .NET, I have that idea - it's perfect for MVVM.

MVVM states for Model-View-ViewModel pattern.
General MVVM Idea

I started with MVVM on WPF apps many years ago and spent a lot of time with MVVMLight and Xamarin, so I immediately saw an advantage of it for Blazor as well.

  1. Like in WPF, Blazor has the most important feature - data binding. In short, you have some data, typically in a collection of some sort, and you want to display it to the user. You can 'bind' your view to the data.
  2. Like in WPF, Blazor has two parts, the .razor page which describes your GUI in HTML, and the code-behind .razor.cs that is tied to it.

This makes Blazor MVVM default for me. So I picked some base components from old MVVM projects which I want to share.

This is ComponentBase which I use for MVVM everywhere.

/// <summary>
/// ComponentBase with DataContext
/// </summary>
public class ContextComponentBase : ComponentBase
{
/// <summary>
///
/// </summary>
protected ViewModelBase DataContext { get; set; }
/// <inheritdoc />
protected override async Task OnInitializedAsync()
{
if (DataContext == null) return;
if (!DataContext.Initialized) // do once
{
await DataContext.InitializeAsync();
DataContext.PropertyChanged += (s, e) => StateHasChanged();
}
await base.OnInitializedAsync();
}
}

The DataContext is quite basic, we only should ensure to initialize it only once for ServerPrerendering mode because it will call OnInitializeAsync twice due to, well, pre-rendering.

public class ViewModelBase : INotifyPropertyChanged
{
/// <summary>
/// Flag indicator if ViewModel was initialized. Set to true by InitializeAsync Method
/// Used to avoid double initialization for ServerPrerendered mode
/// </summary>
public bool Initialized { get; set; }
/// <summary>
/// Initialize view model
/// </summary>
/// <returns></returns>
/// <remarks>This method should not use any JSInterop if render mode is ServerPrerendered</remarks>
public virtual Task InitializeAsync()
{
Initialized = true;
return Task.CompletedTask;
}
/// <summary>
///
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
///
/// </summary>
/// <param name="propertyName"></param>
[NotifyPropertyChangedInvocator]
// ReSharper disable once UnusedMember.Global
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

The only problem here is JavaScript. You cannot use js methods in OnInitializeAsync, and data initialization in OnAfterRender looks wrong to me (at least it's not what docs propose).

And there are things like js-loading indicator which need to be started if the page loaded but the data not.

Much confusing... For now, I simply move all JS initialization to OnAfterRender permanently.

And how you would solve the JS problem in the MVVM pattern?

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
uncle_dallas profile image
Marco Dalla Libera

Hi, interesting topic.
I wrote this post if you like syncfusion.com/blogs/post/mvvm-pat...