Как я использую внедрение зависимости конструктора для предоставления Моделей от набора до их ViewModels?

Я использую внедрение зависимости конструктора в своем приложении WPF, и я продолжаю сталкиваться со следующим шаблоном, так хотел бы получить мнение других людей о нем и услышать об альтернативных решениях.

Цель состоит в том, чтобы обеспечить электричеством иерархию ViewModels к подобной иерархии Моделей, так, чтобы ответственность за представление информации в каждой модели лежала на своей собственной реализации ViewModel. (Шаблон также неожиданно возникает при других обстоятельствах, но MVVM должен сделать для хорошего примера.)

Вот упрощенный пример. Учитывая, что у меня есть модель, которая имеет набор дальнейших моделей:

public interface IPerson
{
    IEnumerable<IAddress> Addresses { get; }
}

public interface IAddress
{
}

Я хотел бы зеркально отразить эту иерархию в ViewModels так, чтобы я мог связать ListBox (или безотносительно) к набору в Человеке ViewModel:

public interface IPersonViewModel
{
    ObservableCollection<IAddressViewModel> Addresses { get; }
    void Initialize();
}

public interface IAddressViewModel
{
}

Дочерний ViewModel должен представить информацию из дочерней Модели, таким образом, он введен через конструктора:

public class AddressViewModel : IAddressViewModel
{
    private readonly IAddress _address;

    public AddressViewModel(IAddress address)
    {
        _address = address;
    }
}

Вопрос, что лучший способ состоит в том, чтобы предоставить дочернюю Модель к соответствующему дочернему ViewModel?

Пример тривиален, но в типичном реальном случае ViewModels имеют больше зависимостей - каждый из которых имеет свои собственные зависимости (и так далее). Я использую Единицу 1.2 (хотя я думаю, что вопрос является актуальным через другие контейнеры МОК), и я использую стратегии представления Меча автоматически найти и обеспечить электричеством соответствующее Представление к ViewModel.

Вот мое текущее решение:

Родительский ViewModel должен создать дочерний ViewModel для каждой дочерней Модели, таким образом, ему добавили метод фабрики к его конструктору, которого он использует во время инициализации:

public class PersonViewModel : IPersonViewModel
{
    private readonly Func<IAddress, IAddressViewModel> _addressViewModelFactory;
    private readonly IPerson _person;

    public PersonViewModel(IPerson person,
                           Func<IAddress, IAddressViewModel> addressViewModelFactory)
    {
        _addressViewModelFactory = addressViewModelFactory;
        _person = person;

        Addresses = new ObservableCollection<IAddressViewModel>();
    }

    public ObservableCollection<IAddressViewModel> Addresses { get; private set; }

    public void Initialize()
    {
        foreach (IAddress address in _person.Addresses)
            Addresses.Add(_addressViewModelFactory(address));
    }
}

Метод фабрики, который удовлетворяет Func<IAddress, IAddressViewModel> интерфейс регистрируется в основном UnityContainer. Метод фабрики использует дочерний контейнер для регистрации IAddress зависимость, которая требуется ViewModel и затем разрешает дочерний ViewModel:

public class Factory
{
    private readonly IUnityContainer _container;

    public Factory(IUnityContainer container)
    {
        _container = container;
    }

    public void RegisterStuff()
    {
        _container.RegisterInstance<Func<IAddress, IAddressViewModel>>(CreateAddressViewModel);
    }

    private IAddressViewModel CreateAddressViewModel(IAddress model)
    {
        IUnityContainer childContainer = _container.CreateChildContainer();

        childContainer.RegisterInstance(model);

        return childContainer.Resolve<IAddressViewModel>();
    }
}

Теперь, когда PersonViewModel инициализируется, это циклично выполняется через каждого Address в Модели и вызовах CreateAddressViewModel() (который был введен через Func<IAddress, IAddressViewModel> аргумент). CreateAddressViewModel() создает временный дочерний контейнер и регистрируется IAddress модель так, чтобы, когда это решает IAddressViewModel от дочернего контейнера AddressViewModel ввели корректный экземпляр через его конструктора.

Это, кажется, хорошее решение меня, поскольку зависимости ViewModels очень ясны, и они являются легко тестируемыми и не знающий о контейнере МОК. С другой стороны, производительность в порядке, но не большая, поскольку много временных дочерних контейнеров может быть создано. Также я заканчиваю с большим количеством очень похожих методов фабрики.

  • Действительно ли это - лучший способ ввести дочерние Модели в дочерний ViewModels с Единицей?
  • Существует ли лучшее (или быстрее) способ сделать это в других контейнерах МОК, например, Autofac?
  • Как этой проблемой занялись бы с MEF, учитывая, что это не традиционный контейнер МОК, но все еще используется для создания объектов?
10
задан alexandrul 19 May 2010 в 09:02
поделиться

2 ответа

В зависимости от контейнера, можете ли вы не указать параметр (названный или иначе) в методе CreateAddressViewModel вашей фабрики?

container.Resolve<IAddressViewModel>(new NamedParameterOverloads() { { "Address", model } };

В зависимости от контейнера вашей фабрике может потребоваться знать имя параметра (TinyIoC и Castle afaik), или он должен был быть последним в списке зависимостей конструктора (YMMV в зависимости от контейнеров), что не очень хорошо, но экономит создание большого количества дочерних контейнеров в быстрой последовательности, и сбор мусора, который будет следовать, и вы по-прежнему получаете DI для всех других ваших зависимостей.

Конечно, это не так, если ваша виртуальная машина также имеет зависимость, требующую того же IAddress, в этом случае дочерний контейнер, вероятно, будет подходящим вариантом, если вы не хотите, чтобы виртуальная машина знала о контейнере.

Обновление: Если вы используете подконтейнер контейнера, который использует "выигрыш последнего регистра" (что, я думаю, использует Unity), то вы можете передать тот же дочерний контейнер в ваш Factory каждый раз, и пусть ваша фабрика просто регистрирует новый IAddress - таким образом вы не будете создавать новый экземпляр UnityContainer в куче для каждой итерации, и он должен сократить сборку мусора, если вы создаете много элементов.

2
ответ дан 4 December 2019 в 04:36
поделиться

Пример приложения ViewModel WPF Application Framework (WAF) показывает, как можно объединить модель и ViewModel. В примере используется MEF в качестве инфраструктуры внедрения зависимостей.

0
ответ дан 4 December 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: