views:

398

answers:

3

I have quite a large number of parent-detail ViewModels in my MVVM application. Something like this:

SchoolsViewModel
  +- SchoolViewModel
      +- LessonViewModel
          +- PupilsViewModel
              +- PupilViewModel
          +- TeacherViewModel
      +- PupilsViewModel
          +- PupilViewModel
              +- LessonsViewModel
      +- TeachersViewModel

And so on...

In addition, a single view model can appear in more than one place, depending on whether the user is browsing by lesson or pupil, etc.

Each child view model is created by the parent view model, and so many of the view models needs to have the dependencies of the child view model passed in. For example the constructor for SchoolsViewModel might be:

SchoolsViewModel(ISchoolsRepository schoolsRepository,
                 ILessonsRepository lessonsRepository,
                 IPupilsRepository pupilsRepository,
                 ITeachersRepository teachersRepository,
                 ...)

Now, the usual way to make all this manageable is to use a DI framework such as StructureMap to pass in all the required arguments to the view model. However, because in this case my application will usually only be creating the SchoolsViewModel this is of limited use.

My first question is, in this case, would you make SchoolsViewModel pass in each dependency to each child view model, or would you make each view model use ObjectFactory.GetInstance() to create the child view models? Perhaps through a factory class to abstract out the dependency on the DI framework?

There is another question relating to this: http://stackoverflow.com/questions/1136052/mvvm-locating-other-viewmodels

EDIT: I've opened a bounty on this as I'd like more opinions.

A: 

The advantage of using dependency injection would be that if SchoolsViewModel itself didn't need to know about, say, the teachersRepository, then it wouldn't even need the reference to it in the constructor. The child ViewModel would still be able to get a handle on the teachersRepository even though the parent knew nothing about it. This prevents the parent ViewModel being polluted with dependencies that it doesn't really need.

Scott Whitlock
+1  A: 

One other alternative...

Look at this LessonViewModel. It depends only on Pupils and Teachers, and knows nothing about PupilParents or any other child object.

public class LessonViewModel
{
    private IPupilsFactory _pupilsFactory;
    private ITeachersFactory _teachersFactory;

    public LessonViewModel(IPupilsFactory pupilsFactory, ITeachersFactory teachersFactory)
    {
        _pupilsFactory = pupilsFactory;
        _teachersFactory = teachersFactory;
    }

    public string Name { get; set; }
    public List<string> PupilNames { get; set; }
    public string TeacherName { get; set; }

    public PupilViewModel GetPupil(string name) 
    {
     return _pupilsFactory.Create(name);
    }

    public TeacherViewModel GetTeacher()
    {
     return _teachersFactory.Create(TeacherName);
    }
}

The lesson factory contains all required dependencies, but it also knows nothing about PupilParents.

public interface ILessonsFactory
{
    LessonViewModel Create(string name);
}

public class LessonsFactory : ILessonsFactory
{
    private ILessonsRepository _lessonsRepository;
    private IPupilsFactory _pupilsFactory;
    private ITeachersFactory _teachersFactory;

    public LessonsFactory(ILessonsRepository lessonsRepository, IPupilsFactory pupilsFactory, ITeachersFactory teachersFactory)
    {
     _lessonsRepository = lessonsRepository;
     _pupilsFactory = pupilsFactory;
     _teachersFactory = teachersFactory;
    }

    public LessonViewModel Create(string name)
    {
     Lesson lesson = _lessonsRepository.Read(name);

     return new LessonViewModel(_pupilsFactory, _teachersFactory) {
      Name = lesson.Name,
      PupilNames = lesson.PupilNames,
      TeacherName = lesson.TeacherName
     };
    }
}
alex2k8
But I am afraid this is too complex... It is better to have one EducationFactory combining all whose factories.
alex2k8
A: 

Perhaps I am not seeing the big picture here? Can't you use StructureMap and all of it's underpinnings to take care of this dirty work for you? You can use StructureMap's constructor injection to take care of all of this work. By hooking up an interface and all of the interfaces that it and it's children are dependant upon to StructureMap - and putting the various dependant interfaces into the constructor of the various objects that need them...when you instantiate object 1 which has a dependancy on object 2 which in turn has a dependancy on object 3...StructureMap will take care of it all.

Maybe I am missing something?

Andrew Siemer