Question

I am writing a WPF application using MEF and a third-party library called MEFedMVVM.

I am attempting to create a design whereby a parent view model has a collection of child view models, and I wish to use the view-model-first approach as this keeps the views outside of the view models thereby keeping the code more view model-centric and more unit testable.

I have read this discussion and this discussion regarding using DataTemplate for the view, and also Reed Copsy, Jr's suggestion here to use a generic view to view model mapping resource. But, I'm struggling to actually implement something that works.

My parent view is very simple:

<UserControl x:Class="MyParentView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:meffed="clr-namespace:MEFedMVVM.ViewModelLocator;assembly=MEFedMVVM.WPF"
             meffed:ViewModelLocator.ViewModel="MyParentViewModel" />

The parent view model derives from a base type that implements IContextAware:

[ExportViewModel("MyParentViewModel")]
public class MyParentViewModel : ViewModelBase
{
    [ImportingConstructor]
    public MyParentViewModel()
    {
        var myChildVM = ServiceLocator.Current.GetInstance<MyChildViewModel>());
    }
}

This is the child view model:

[Export(typeof(MyChildViewModel))]
[ExportViewModel("MyChildViewModel", true)]
public class MyChildViewModel : ViewModelBase
{
}

And this has a corresponding view:

<UserControl x:Class="MyChildView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:meffed="clr-namespace:MEFedMVVM.ViewModelLocator;assembly=MEFedMVVM.WPF"
             meffed:ViewModelLocator.ViewModel="MyChildViewModel" />

Initially, I thought that specifying the second Boolean parameter on ExportViewModel attribute for MyChildViewModel would make everything work using a view-model-first approach as my views and view models are MEFed together in the views' XAML code. However, turns out this is not the case, and what I actually get passed in to IContextAware.InjectContext() when I instantiate a MyChildViewModel object in the MyParentViewModel constructor is a MyParentView object. Not a MyChildView object as I was expecting and hoping. Clearly, I need to add something to wire them up together. Could anyone provide an example on how to do this?

Thanks!

Was it helpful?

Solution

When you really want to use view-model-first then you should do:

[ExportViewModel("MyParentViewModel")]
public class MyParentViewModel : ViewModelBase
{
    // Create property for your child vm
    public MyChildViewModel Child {get; private set}

    // If you do MEF use constructor injection instead of servicelocator
    [ImportingConstructor]
    public MyParentViewModel(MyChildViewModel child)
    {
        this.Child = child;
    }
 }

then define a datatemplate for your childvm

 <DataTemplate DataType="{x:Type local:MyChildViewModel}">
     <view:MyChildViewUserControl />
 </DataTemplate>

in your MainView you know where you want to show the child data, otherwise you wouldn't need the child property ;) so simply put a ContentControl where the Child data should go and bind to your property.

e.g.

<TabControl>
   <TabItem Header="MyChildData">
      <ContentControl Content="{Binding Child}" />
   </TabItem>
</TabControl>

PS: Code is written without IDE, so errors possible :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top