views:

191

answers:

1

I created a MVVM test application which at runtime reads an XML file to create a menu dynamically and based on what the user selects, loads in that page's UserControl dynamically. The result is a nice MVVM pattern that allows you to have one View/ViewModel pair per page all defined in an XML file. Very nice.

So now I just added the ability for the developer to create a button on one page that goes to another page. The way I do this is in the MainViewModel I build the collection of ViewModels in the ObservableCollection and when I build each, I inject the MainViewModel itself (this) into each UserControl-ViewModel's constructor. This way each UserControl has inside of it the MainViewModel so that the developer can manipulate the application (e.g. call SwitchPage(idCode)) via the MainViewModel.

Also any global state that I need to save I can save in the MainViewModel to which each UserControl has access.

Also, each UserControl (PageItem) has full access to each of the other UserControls which gives me basically control of anything in the application from any UserControl, something that I have been trying to achieve in an MVVM application for a long time.

So my question is: Is this kind of ViewModel injection a useful/known pattern or are there problems with injecting a ViewModel into its child ViewModels? It seems recursive to me but seems to work fine and gives me the functionality I want so far. From what I have learned from the Composite Application Library architecture, this seems to be something similar that is going on there, and that e.g. in the code below I could inject other application objects into my ViewModels as they need them.

public MainViewModel()
{

    PageItems pageItems = PageItems.Create("all");

    foreach (PageItem pageItem in pageItems.Collection)
    {
        string assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
        string viewModelName = assemblyName + ".ViewModels.PageItem" + StringHelpers.ForcePascalNotation(pageItem.IdCode) + "ViewModel";
        var type = Type.GetType(viewModelName);
        var viewModel = Activator.CreateInstance(type, this, pageItem) as ViewModelPageItemBase;
        AllPageItemViewModels.Add(viewModel);
    }

    CurrentPageItemViewModelIndex = 0;
    LoadCurrentPageItemViewModel();
}
+5  A: 

I don't see this as wrong or right, but more about how coupled your design is. I normally start with the approach you mentioned (child VM references parent VM) and then decouple if I find it gets too unwieldy. Your first choice doesn't necessarily have to be your last - you can refactor your code as it evolves.

Possible alternatives are:

  • child VM raises event that parent listens to (observer pattern). Parent VM knows children intimately, but child does not know parent.
  • child VM publishes event on event hub that parent listens to (mediator pattern). Neither child nor parent are intimately aware of each other. They are aware only of the mediator.

HTH, Kent

Kent Boogaart