I have a C# MVVM app (Avalonia with ReactiveUI if that matters) in which a user can create, modify and close a project. Different parts of the application need to be notified when a project is un/loaded and properly react to this.
My initial solution was to create a ProjectViewModel that I can pass around the application to leverage its property notification mechanism but it feels more like a stateful service that implements INotifyPropertyChanged than an actual ViewModel.
The ProjectViewModel has commands (to create/save/load/unload a project) and nullable properties holding data related to the project, if any. I would then pass this VM to any part of the application that needs to know about the project.
A ViewModel with a dependency on the ProjectViewModel could look like this:
public class ConfigurationExplorerViewModel
{
private readonly ProjectViewModel _projectViewModel;
public ConfigurationExplorerViewModel(ProjectViewModel projectViewModel)
{
_projectViewModel = projectViewModel;
Configs = new();
// Subscribing to when the project changes in projectViewModel.
_projectViewModel.WhenAnyValue(x => x.Project)
.Subscribe(RefreshProject);
}
private void RefreshProject(IProject? project)
{
Configs.Clear();
if (project is null)
{
return;
}
foreach (var config in project.Configs)
{
Configs.Add(new ConfigViewModel(config));
}
}
public ObservableCollection<ConfigViewModel> Configs { get; }
}
I'm starting to have doubts about this for a couple of reasons:
- This ViewModel is not bound to any view and feels more like a stateful service that implements
INotifyPropertyChanged. - Its commands could easily be moved to the MainViewModel where they would make more sense.
- It's only passed to other ViewModels so that they can access the Project properties and subscribe to the PropertyChanged event when it's un/loaded. For instance, a view could update to show or hide a "No Project Loaded" label.
- The more the application grows, the more I need to use null checks on the Project properties wherever they are needed.
I seems like I'm not separating concerns properly. Does it make sense for a ViewModel to be used this way or is it a code smell that should be addressed?