Creating child view models using MEF

I have a traditional MVVM approach, for example, a view model called "PatientManagementViewModel" that is used in the "PatientManagementView" view. Everything is entered using MEF, so I myself do not create any instances.

Now suppose that "PatientManagementViewModel" has the "Patients" property, which is the ObervableCollection "PatientViewModel". Now I create an instance of "PatientViewModel" and pass the selected patient as follows:

var patientViewModel = _container.GetExportedValue<IPatientViewModel>(); patientViewModel.Patient = patient; 

This works, however, I was wondering if that makes sense. It would be better to pass the patient to the constructor, because the "PatientViewModel" cannot exist without the patient:

 var patientViewModel = new PatientViewModel(patient); 

but then I cannot use dependency injection.

So the question is: does it make sense to introduce a subviewmodel, or should I just introduce the main view model and instantiate all submatrix models without injection?

+4
source share
1 answer

You can do the following. You can create your child view model using a regular constructor, and then call ComposeParts on the instance to add everything:

 var patientViewModel = new PatientViewModel(patient); _container.ComposeParts(patientViewModel); 

But doing it every time is not very good for a number of reasons. To solve this scenario and encapsulate the use of MEF, I created a helper service for creating view models. It is called IViewModelFactory , and here is what it looks like:

 [Export(typeof(IViewModelFactory))] [PartCreationPolicy(CreationPolicy.Shared)] internal class ViewModelFactory : IViewModelFactory { [ImportingConstructor] public ViewModelFactory(CompositionContainer container) { Contract.Requires(container != null); Container = container; } protected CompositionContainer Container { get; private set; } public T Create<T>(params object[] args) where T : class { T result; try { bool populateDependencies = false; if (args == null || args.Length == 0) { // There are no parameters for contructor, so // try to create an instance by asking the container. result = Container.GetExportedValueOrDefault<T>(); if (result == null) { // The view model is not exported. Just create an instance using reflection // and then populate all the dependencied using the container. result = Activator.CreateInstance<T>(); populateDependencies = true; } } else { // There are constructor parameters. Create an instance using those parameters // and then populate all the dependencied using the container. result = (T)Activator.CreateInstance(typeof(T), args); populateDependencies = true; } // Populate dependencies if needed if (populateDependencies) { Container.ComposeParts(result); } // Initialize the object if applicable var initializable = result as IInitializable; if (initializable != null) { initializable.Initialize(); } } catch (Exception ex) { throw new ViewModelCreationException( string.Format( "Unable to create and configure an instance of view model of type {0}. An error occured. See inner exception for details.", typeof (T)), ex); } return result; } } 

Using this factory, you can create child-view models as follows:

 var patientViewModel = ViewModelFactory.Create<PatientViewModel>(patient); 

The disadvantage is that when using constructor parameters, you lose compilation time checking for parameter types, quantity, order, etc.

+1
source

Source: https://habr.com/ru/post/1341970/


All Articles