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.
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.
- 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.
- 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?
Top comments (1)
Hi, interesting topic.
I wrote this post if you like syncfusion.com/blogs/post/mvvm-pat...