In this article you learn how to use MvvmGen's EventAggregator to communicate between ViewModels.
An event in MvvmGen can be anything, and the type identifies the event. Typically, with C# 9.0 or later, you define an event with a simple record like this:
public record EmployeeSavedEvent(int id, string? FirstName);To publish an event, you inject an MvvmGen.Events.IEventAggregator into your
ViewModel with the Inject attribute. Then you use the generated
EventAggregator property like you see it in the Save method of this ViewModel:
[Inject(typeof(IEventAggregator))]
[ViewModel(typeof(Employee))]
public partial class EmployeeViewModel
{
[Property] private string _updateComment;
partial void OnInitialize()
{
Model = new Employee
{
FirstName = "Thomas Claudius",
IsDeveloper = true
};
}
[Command(CanExecuteMethod = nameof(CanSave))]
private void Save()
{
EventAggregator.Publish(new EmployeeSavedEvent(Model.Id, Model.FirstName));
}
[CommandInvalidate(nameof(FirstName))]
private bool CanSave()
{
return !string.IsNullOrEmpty(FirstName);
}
}To subscribe from a ViewModel to an event, you implement the generic
IEventSubscriber interface that defines an OnEvent method:
[ViewModel]
public partial class NavigationViewModel : IEventSubscriber<EmployeeSavedEvent>
{
public void OnEvent(EmployeeSavedEvent eventData) { }
}When you look at the generated code of this NavigationViewModel class,
you see that an IEventAggregator constructor parameter is created,
and in the constructor the RegisterSubscriber method is called
on the IEventAggregator to register the ViewModel instance as an event subscriber:
partial class NavigationViewModel : ViewModelBase
{
public AnotherViewModel(MvvmGen.Events.IEventAggregator eventAggregator)
{
eventAggregator.RegisterSubscriber(this);
this.OnInitialize();
}
partial void OnInitialize();
}This means that you just implement the IEventSubscriber interface,
and your OnEvent method is called when the event was published.
There’s nothing more for you to do. If you need to subscribe to multiple events,
you can implement the IEventSubscriber interface multiple times,
or you use overloads of this interface that have multiple generic type parameters.
If you need to publish events in addition, you use the Inject attribute
to inject the IEventAggregator, so that you can call EventAggregator.Publish
in your code.
If you want to publish an event when a property changes, you could use
the PropertyCallMethod attribute to do publish the event in a custom method.
But an easier way is the PropertyPublishEvent attribute.
The following field has that attribute set. Beside the mandatory event type,
you can specify optional EventConstructorArgs and an optional PublishCondition:
[PropertyPublishEvent(typeof(EmployeeNavigationSelectedEvent),
EventConstructorArgs = "value.Id",
PublishCondition = "value is not null")]
[Property]
private NavigationItemViewModel? _selectedItem;The generated property for the field above looks like this:
public EmployeeManager.ViewModel.NavigationItemViewModel? SelectedItem
{
get => _selectedItem;
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
if (value is not null)
{
EventAggregator.Publish(new EmployeeManager.ViewModel.Events.EmployeeNavigationSelectedEvent(value.Id));
}
}
}
}Next, let's look at how to generate a ViewModelFactory.