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!

Était-ce utile?

La 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 :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top