Создание моделей дочернего вида при использовании MEF - PullRequest
4 голосов
/ 02 марта 2011

У меня есть традиционный подход MVVM, например, модель представления с именем PatientManagementViewModel, которая используется представлением с именем PatientManagementView. Все вводится с использованием MEF, поэтому я сам не создаю ни одного экземпляра.

Теперь предположим, что у PatientManagementViewModel есть свойство Patients, которое является ObervableCollection для PatientViewModel. То, что я делаю сейчас для создания экземпляра PatientViewModel и передачи выбранного пациента, выглядит так:

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

Это работает, однако мне было интересно, имеет ли это смысл. Было бы лучше передать пациента конструктору, потому что «PatientViewModel» не может существовать без пациента:

var patientViewModel = new PatientViewModel(patient);

но тогда я не могу использовать инъекцию зависимостей.

Таким образом, вопрос заключается в следующем: имеет ли смысл внедрять подвидомодель или мне следует только внедрить модель основного представления и создать экземпляр всех подвидомоделей без внедрения?

1 Ответ

1 голос
/ 02 марта 2011

Вы можете сделать следующее.Вы можете создать свою дочернюю модель представления, используя обычный конструктор, а затем вызвать ComposeParts в экземпляре, чтобы внедрить все:

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

Но делать это каждый раз не очень хорошо по разным причинам.Для решения этого сценария и для инкапсуляции использования MEF я создал вспомогательный сервис для создания моделей представлений.Она называется IViewModelFactory, и вот как это выглядит:

[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;
    }
}

Используя эту фабрику, вы можете создавать модели дочернего вида, такие как:

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

Недостатком является то, что, когдавы используете параметры конструктора, вы теряете проверку во время компиляции для типов параметров, количества, порядка и т. д.

...