This is the third article in the MVVM Made Easy series with a focus on Messaging in .NET MAUI and Blazor Hybrid apps.
Here are the links to other articles in this series.
Although the fundamentals remain the same, the preceding articles were published after the initial version of the MVVM Toolkit, and a lot has transpired since then. An updated article is being prepared and published soon.
Blazor Hybrid represents an exemplary integration of cross-platform .NET MAUI and the Blazor components.
It facilitates the utilization of C# expertise in the development of various applications, including those for Desktop, Mobile, and Web platforms.
However, there are instances when these disparate components must communicate with one another for the integration to function effectively.
Whenever the necessity arises to facilitate communication between loosely coupled components, messaging represents the most effective solution.
CommunityToolkit.Mvvm, aka Microsoft MVVM Toolkit, provides an excellent solution that facilitates messaging with exceptional efficiency.
This is available in two distinct implementations:
- StrongReferenceMessenger
- WeakReferenceMessenger
Both adhere to the IMessenger interface, which delineates the requisite methods essential for effective messaging – Register(), Send(), and Unregister().
In terms of performance, the StrongReferenceMessenger demonstrates superior capabilities, albeit at the expense of strong references.
The component anticipated to receive the message must first Register for the specified message type and subsequently await the transmission of messages from the other component.
Components are capable of transmitting messages through the Send() method.
This messaging instance can be utilized as Static members or DI-injected instances as shown below.
// Access via static members
StrongReferenceMessenger.Default.Send(new ShoppingCartUpdatedMessage(product));
WeakReferenceMessenger.Default.Send(new ShoppingCartUpdatedMessage(product));
// Access via DI
// First add it to the DI container
// Replace the WeakReferenceMessenger.Default with
// StrongReferenceMessenger.Default to change the implementation instance
builder.Services.AddSingleton<IMessenger>(WeakReferenceMessenger.Default);
// Actual use ...
public class ShoppingCartUpdatedMessage : ValueChangedMessage<Product>
{
}
public class ProductViewModel(IMessenger messenger) : BaseViewModel
{
[RelayCommand]
private void AddToCart()
{
// Custom business logic
// product is an user-defined object
// Send the message
messenger.Send(new ShoppingCartUpdatedMessage(product));
}
}
The
ObservableRecipientis a specialized type that extendsObservableObject, offering built-in support for utilizing theIMessengertype.By default, it utilizes the instance of
WeakReferenceMessenger; however, an overloaded constructor is available that permits updating to an instance ofStrongReferenceMessenger.Access the messenger instance through the read-only
Messengerproperty in types derived from ObservableRecipient.
// Only relevant code is shown here
public abstract class ObservableRecipient : ObservableObject
{
protected ObservableRecipient : this(WeakReferenceMessenger.Default) {}
protected ObservableRecipient(IMessenger messenger) => Messenger = messenger;
protected IMessenger Messenger { get; }
}
On an additional note, this WeakReferenceMessenger is the recommended alternative for messaging in .NET MAUI, given that the classic MessagingCenter is now deprecated.
Communicate from Blazor to .NET MAUI:
BlazorWebView serves as an entry point that facilitates the integration of .NET MAUI and Blazor components in a Hybrid app.
Since they’re loosely coupled by design, there is no direct method to facilitate communication from a Blazor component to .NET MAUI, the MVVM Toolkit Messaging proves to be useful in such scenarios.
In the Blazor component, say Product.razor:
@page "product"
@inject IMessenger messenger
@code {
private void AddToCart()
{
// product is a user defined object
messenger.Send(new ShoppingCartUpdatedMessage(product));
// Can be accessed statically too
// WeakReferenceMessenger.Default.Send(new ShoppingCartUpdatedMessage(product));
}
}
In .NET MAUI:
// Only relevant code is shown
public partial class HomePage : ContentPage
{
private readonly IMessenger messenger;
public HomePage(IMessenger messenger)
{
InitializeComponent();
this.messenger = messenger;
}
protected override void OnNavigatedTo(NavigatedToEventArgs args)
{
base.OnNavigatedTo(args);
// First, register to begin receiving messages.
messenger.Register<ShoppingCartUpdatedMessage>(this, OnReceived);
}
// The method is invoked upon the receipt of a message of the type ShoppingCartUpdatedMessage.
private void OnReceived(object recipient, ShoppingCartUpdatedMessage message)
{
// Process the message
// Access the Product object via message.Value property
}
// Unregister it, if no longer necessary.
// messenger.Unregister<ShoppingCartUpdatedMessage>(this);
}
In conclusion, this MVVM toolkit is not limited to Blazor or MAUI; rather, it can be utilized to communicate among disparate .NET components, as it works independently of any external dependencies.
Further Reading:
Happy coding. Stay connected as we continue to learn and share the experiences from this exciting journey of being a .NET developer.