Korzystam z wtrysku zależnego od konstruktora w mojej aplikacji WPF i nadal używam następującego schematu, więc chciałbym poznać zdanie innych ludzi na ten temat i usłyszeć o alternatywnych rozwiązaniach.Jak używać wtrysku zależnego od konstruktora do dostarczania modeli z kolekcji do ich modeli ViewModels?
Celem jest połączenie hierarchii ViewModels z podobną hierarchią modeli, aby odpowiedzialność za prezentowanie informacji w każdym modelu spoczywała na własnej implementacji ViewModel. (Wzór ten pojawia się również w innych okolicznościach, ale MVVM powinna stanowić dobry przykład.)
Oto uproszczony przykład. Biorąc pod uwagę, że mam model, który posiada kolekcję kolejnych modeli:
public interface IPerson
{
IEnumerable<IAddress> Addresses { get; }
}
public interface IAddress
{
}
Chciałbym odzwierciedlać tę hierarchię w ViewModels tak, że mogę powiązać ListBox (lub cokolwiek) do kolekcji w osobie ViewModel:
public interface IPersonViewModel
{
ObservableCollection<IAddressViewModel> Addresses { get; }
void Initialize();
}
public interface IAddressViewModel
{
}
dziecko ViewModel musi przedstawić informacje od dziecka model, więc jest wstrzykiwany za pomocą konstruktora:
public class AddressViewModel : IAddressViewModel
{
private readonly IAddress _address;
public AddressViewModel(IAddress address)
{
_address = address;
}
}
Chodzi o to, co jest najlepszym sposobem dostarczyć model dziecka do odpowiedniego dziecka ViewModel?
Przykład jest banalny, ale w typowym przypadku rzeczywistym modele ViewModels mają więcej zależności - z których każda ma swoje własne zależności (i tak dalej). Używam Unity 1.2 (chociaż myślę, że pytanie dotyczy innych kontenerów IoC) i używam strategii widoku Caliburn, aby automatycznie znaleźć i podłączyć odpowiedni View do ViewModel.
Oto mój obecny rozwiązanie:
Rodzic ViewModel musi stworzyć dziecku ViewModel dla każdego modelu dziecięcej, więc ma fabrykę metoda dodaną do jego konstruktora których używa podczas inicjalizacji:
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));
}
}
Metoda fabryczna, która spełnia wymagania interfejsu Func<IAddress, IAddressViewModel>
, jest zarejestrowana w głównej wersji UnityContainer
. Metoda fabryka wykorzystuje pojemnik dziecko zarejestrować zależność IAddress
, który jest wymagany przez ViewModel a następnie rozwiązuje ViewModel dziecko:
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>();
}
}
Teraz, gdy PersonViewModel
jest inicjowany, to pętle przez każdy Address
w modelu i połączeń CreateAddressViewModel()
(który został wprowadzony za pomocą argumentu Func<IAddress, IAddressViewModel>
). CreateAddressViewModel()
tworzy tymczasowy kontener podrzędny i rejestruje model IAddress
, dzięki czemu po rozwiązaniu IAddressViewModel
z kontenera podrzędnego AddressViewModel
otrzymuje poprawną instancję wstrzykniętą za pośrednictwem jej konstruktora.
To wydaje się być dobrym rozwiązaniem dla mnie, ponieważ zależności ViewModels są bardzo jasne i są łatwe do sprawdzenia i nieświadome pojemnika IoC. Z drugiej strony wydajność jest w porządku, ale nie jest tak duża, ponieważ można utworzyć wiele tymczasowych kontenerów podrzędnych. Również kończę z wieloma bardzo podobnymi metodami fabrycznymi.
- Czy to najlepszy sposób, aby wstrzykiwać dziecku Modele do dziecka ViewModels with Unity?
- Czy jest lepszy (lub szybszy) sposób, aby to zrobić w innych kontenerach IoC, np. Autofac?
- W jaki sposób problem ten został rozwiązany za pomocą MEF, biorąc pod uwagę, że nie jest to tradycyjny kontener IoC, ale nadal jest używany do komponowania obiektów?
Jak podkreślasz, określanie parametrów nie działa, jeśli którakolwiek z zależności wymaga modelu, który był dla mnie showstopper. Ponowne użycie kontenera podrzędnego jest jednak możliwe. – GraemeF