Reputation: 4497
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!
Upvotes: 0
Views: 2911
Reputation: 22445
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 :)
Upvotes: 4