Pattern for ViewModel creation.

Topics: UI Architecture
Aug 1, 2011 at 6:56 AM

Ok, I'm trying to decide the best way to new up a ViewModel from within another ViewModel. Where possible I'm trying to do constructor injection of services into the ViewModels and using the IoC to glue everything together.

So, the various methods I have are:

  • Simply use IoC.Get<ViewModel>(). Using the IoC like this isn't really recommended.
  • Pass all relevant services for the child ViewModel into the parent ViewModel and store them locally. Then create the child ViewModel with manual injection. This will cause the parent ViewModels constructor to grow stupidly large.
  • Have some sort of ViewModelFactory service which creates new ViewModels for you. This is basically a pretty wrapper around the IoC.
  • ???

None of these solutions really appeal to me. I'm also trying to architect a solution that is easily testable.

How do people create ViewModels in their CM projects? Is there a commonly accepted pattern for this?

Thanks

Aug 1, 2011 at 7:18 AM

I prefer the injection by constructor method. If the parameters tend to grow, it means that the view-model depends simply on too much stuff. Keep as few dependencies as you need, and try to identify dependencies that are shared among your view-model hierarchy, so that you can re-use them from a parent view-model, if possible... sometimes I prefer to drill up the view-model tree to invoke methods on the shell (that are just used to wrap service dependencies), instead of replicating the same dependency over and over again... it really depends on the scenario.

Another possible approach, if you are using MEF directly, is to define dependencies at property level, instead of at the constructor level.

Just to answer your last question: I hardly belive that there is a widely accepted pattern to leverage view-model dependencies. You need to tailor a solution depending on your scenario.

Aug 1, 2011 at 7:29 AM

I don't think I made my second scenario clear enough. So I'll use an example.

Say I have a ShellViewModel

public class ShellViewModel {

    public ShellViewModel(ISomeService someService) {
    }

    public void SomeMethod() {
        this.ActivateItem(new ChildViewModel());
    }

}

Now lets say I want to provide another Service to the ChildViewModel. My ShellViewModel changes to:

public class ShellViewModel {

    private IChildService childService;

    public ShellViewModel(ISomeService someService, IChildService childService) {
        this.childService = childService;
    }

    public void SomeMethod() {
        this.ActivateItem(new ChildViewModel(childService));
    }

}

And now my ShellViewModel is taking a service simply to pass it to the child when it's created. Obviously this isn't desirable.

Aug 1, 2011 at 7:39 AM
Edited Aug 1, 2011 at 7:40 AM

How much does your child view-model know about its environment? I mean, does it know that a ShellViewModel is its parent? If so, you could just define the childService dependency to the parent, and let the child use it directly from there. That is, if the service is needed by both parent and children.

If it is not needed by the parent (the child service is not used by the parent, and is just passed as a dependency to its children), or if you prefer to make your child view-model completely agnostic of the environment, then your only option is to use a factory method to create it.

In your example, I would definitely use a factory method: the service is not needed by the parent, but required only by the child, so there is no need for the parent to have a dependency over it.

Aug 1, 2011 at 7:45 AM

Yeah I figured a ViewModel factory would be the best way to go here.

My next problem then is how do you write said factory? It's very tempting to just write it as

public class ViewModelFactory : IViewModelFactory {

    public TViewModel CreateViewModel<TViewModel>() {
        return IoC.Get<TViewModel>();
    }

}

Aug 1, 2011 at 7:50 AM

Why not? :)

I agree that this way you are just wrapping the IoC, but keep in mind that with this approach you are really separating the framework from the application logic. You could decide to change the implementation of the factory later on, without modifying all dependent view-models, or change the factory signature and use compiler errors to make sure that all references are updated.

Keep it simple, and grow in complexity as needed. :)

Aug 1, 2011 at 10:47 AM

You can also give a VM factory in the form of a func<>.

You have to wire the func in your container, it depends on the container you use how easy this is.

public class ShellViewModel {

    private Func<ChildViewModel> childViewModelFactory;

    public ShellViewModel(ISomeService someService, Func<ChildViewModel> childViewModelFactory) {
        this.childViewModelFactory = childViewModelFactory;
    }

    public void SomeMethod() {
var childViewModel = childViewModelFactory();
 ActivateItem(childViewModel); } }