Reputation: 587
Our new project started out with View first pattern using ViewModelLocator to marry the view with the viewmodel.
I'd like to change to a ViewModel first pattern.
Here is my view model constructor:
public DeviceSelectionViewModel(IDataModel dataModel, IMessenger messenger)
{
if (dataModel == null) throw new ArgumentNullException("dataModel");
if (messenger == null) throw new ArgumentNullException("messenger");
Selector = new PlantDataTemplateSelector();
PlantSelector = new PlantNodesSelector();
Plants = new List<Plant>(0);
messenger = messenger;
messenger.Register<PlantDataLoadedMessage>(this, m => DispatcherHelper.CheckBeginInvokeOnUI(() => OnPlantDataLoaded(m.Plants)));
RefreshData(_dataModel);
}
Here is how I'm now selecting the appropriate ViewModel using ViewModel first.
public class MainViewModel : Module
{
public MainViewModel()
{
SelectedView = new DeviceSelectionViewModel();
}
public ViewModelBase SelectedView { get; set; }
}
With View first, I never directly called the ViewModel via code so the Constructor Dependency Injection worked fine.
Now that I'm calling the ViewModel via a controller ViewModel, it wants the 2 parameters for the ViewModel Constructor.
Is the proper play here to hold the references in the controller view model and pass them into the constructor? I'm missing something here with how DI works in this scenario?
I'm still putting the pieces together with DI(Ninject) and MVVM, so be kind :)
Upvotes: 1
Views: 898
Reputation: 13983
We had the same issue.
You have the following choices:
MainViewModel
creates DeviceViewModel
providing the values for required parametersMainViewModel
gets already resolved DeviceViewModel
The first variant increases coupling in case when DeviceViewModel
is exposed only for View bindings. If MainViewModel
communicates with DeviceViewModel
then coupling is already implied unless MainViewModel
sees DeviceViewModel
through some interface what inevitably requires the second option.
Another problem of the 1st approach is that in some cases nested VM can require more values for its creation as parent VM needed.
This can be solved by extending parent VM constructor to contain these additional parameters. But when (though never in practice) building complex VM graphs root VM's constructor can become bloated.
We now have a mix of both options.
All our ViewModels inherit from ViewModelBase
abstract class. It has several overloaded constructors and most of them get IViewModelFactory
as an input. So we can ask the factory to create ViewModel
wee need. Wee decided not to worry about the returned type and just return the type of created ViewModel incapsulating only its creation. So it is not true DI.
We also use Messanger but our ViewModels cannot send messages explicitly and can only subscribe to the messages. We did so intentionally as a way to restrict a set of messages particular VM can send (and even subscribe to).
Upvotes: 1