Experiments using MEF, MVVM and Silverlight 4 Beta – Part 3: Part Creator and Creation Policy
Note – this is a multi part post:
In the last post I’ve inserted custom attributes in my MVVM implementation using MEF, in the meantime some awesome discussions and inputs on Twitter by Glenn Block have highlighted new interesting scenarios.
First of all, object instances are shared by default in MEF, however you can change this behaviour using a dedicated attribute named PartCreationPolicy during the export phase:
[PartCreationPolicy(CreationPolicy.NonShared)]
[ExportMainPageVMAttribute]
public class MainPageViewModel : ViewModelBase
{ .... class definition here .... }
In this way, all the ViewModel instances exported by MEF will be not shared and different views shall use different VM objects without any side-effect.
Another rule of thumb is avoiding calling the container directly in order to simplify architecture, as stated in this great article by Nicholas Blumhardt. This step requires the introduction of a new actor available in MEF: the declarative context adapter PartCreator<T>.
The first place in which I’ve used PartCreator<T> is in the code for the composition phase:
public MainPageView()
{
InitializeComponent();
PartInitializer.SatisfyImports(this);
this.DataContext = mainPageViewModelCreator.CreatePart().ExportedValue;
}
[ImportMainPageVMAttribute]
public PartCreator<object> mainPageViewModelCreator { get; set; }
The VM instance is now retrieved calling the CreatePart() method of the PartCreator, instead of calling directly the container.
The same approach is now used to retrieve the instances relative to the aViewModelProperty and aSampleCommand:
[PartCreationPolicy(CreationPolicy.NonShared)]
[ExportMainPageVMAttribute]
public class MainPageViewModel : ViewModelBase
{
/// <summary>
/// Default constructor
/// </summary>
public MainPageViewModel() { }
/// <summary>
/// A Part Creator for the aViewModelProperty
/// </summary>
[Import("aViewModelPropertyTextProvider")]
public PartCreator<string> aViewModelPropertyCreator { get; set; }
/// <summary>
/// A sample property
/// </summary>
private string _aViewModelProperty;
public string aViewModelProperty
{
get
{
if (_aViewModelProperty == null)
{
_aViewModelProperty = aViewModelPropertyCreator.CreatePart().ExportedValue;
}
return _aViewModelProperty;
}
set { _aViewModelProperty = value; NotifyPropertyChanged("aViewModelProperty"); }
}
/// <summary>
/// A Part creator for the sample command
/// </summary>
[Import(typeof(ICommand))]
public PartCreator<ICommand> aSampleCommandCreator { get; set; }
/// <summary>
/// A sample command
/// </summary>
public ICommand aSampleCommand
{
get
{
return aSampleCommandCreator.CreatePart().ExportedValue;
}
}
/// <summary>
/// A simple property
/// </summary>
private string _aSimpleProperty = "A simple property sample";
public string aSimpleProperty {
get { return _aSimpleProperty; }
set { _aSimpleProperty = value; NotifyPropertyChanged("aSimpleProperty"); }
}
}
The VM instance is then created in xaml using a ViewModelPartCreator class:
/// <summary>
/// Get the ViewModel instance via the PartCreator<T>
/// </summary>
public class ViewModelPartCreator
{
public ViewModelPartCreator() { }
[ImportMainPageVMAttribute]
public PartCreator<object> mainPageViewModelPartCreator { get; set; }
/// <summary>
/// Get the imported Instance of the ViewModel
/// </summary>
public object GetVMInstance
{
get
{
PartInitializer.SatisfyImports(this);
return mainPageViewModelPartCreator.CreatePart().ExportedValue;
}
}
}
MainPageView.xaml:
<UserControl x:Class="SL4_MVVM_MEF.Views.MainPageView"
.......
xmlns:partCreators="clr-namespace:SL4_MVVM_MEF.PartCreators"
>
<UserControl.DataContext>
<partCreators:ViewModelPartCreator/>
</UserControl.DataContext>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Text="A ViewModel property MEF imported:" FontWeight="Bold"/>
<TextBox Text="{Binding GetVMInstance.aViewModelProperty}" Margin="10,0,0,0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Text="A ViewModel simple property:" FontWeight="Bold"/>
<TextBox Text="{Binding GetVMInstance.aSimpleProperty}" Margin="10,0,0,0"/>
</StackPanel>
<Button x:Name="CommandButton" Command="{Binding GetVMInstance.aSampleCommand}" CommandParameter="This is a Command parameter"
Content="Click me!" Margin="0,10" Width="200"/>
</StackPanel>
</UserControl>
As usually the source code is available for download here.
A special thanks to Glenn Block for the awesome suggestions on Twitter
Happy Silverlighting!





December 7th, 2009 at 08:11
Nice post, but I have to critique it a bit
I may be missing something, but it looks like PartCreator is being used here to create a single VM for a view rather than just importing it. If that is the case, then you really shouldn’t be using PartCreator rather you should be just importing the VM directly. This benefits you in several ways including static analysis (which MEF performs).
The places PartCreator is interesting to use is when you need to spin up new instances dynamically after the part has been composed. An example of this would be if you need to create new Order views every time someone clicks on the “New Order” button. This happens within a part (like the OrdersController) after it has been composed, so PartCreator is the right thing.
In the channel 9 video we did on MEF Preview 7, I showed an example of an OrderEntry scenario that uses PartCreator in a similar fashion. In this case orders are created within the MainPageVM each time the NewOrder command is called.
You can get to the talk here:
http://channel9.msdn.com/shows/10-4/10-4-Episode-32-MEF-Preview-7/
Thanks
Glenn
December 7th, 2009 at 13:53
Hi Glenn, as usually thanks for the great suggestions!
I agree with you for the import approach of the VM in the case of a single instance, I’m currently experimenting the possibility to strong decouple all the objects involved in the pattern (including commands and properties) and also the association (marriage?) between the xaml and different viewmodel instances. I’ve watched the video, excellent, I’ll investigate further! Thanks
December 7th, 2009 at 16:56
Not sure this is a great example of the PartCreator class; a view model has the same lifetime as the control bound to it so there’s no reason for a PartCreator, it’s use is the ability to dynamically resolve types without the need to access the container directly as per Nicholas Blumhardt’s example.
December 7th, 2009 at 17:14
Hi Owain, thanks for the feedback!
December 7th, 2009 at 17:53
[...] the last post I’ve updated the MEF MVVM example inserting some PartCreator<T> experiments and [...]
December 7th, 2009 at 18:14
Hi Davide
As far as wiring up the V and the VM. One clean way to do it is to just externalize it in an attached behavior. There have been several approaches at doing this. I am working on one now for MEF, basically the behavior pulls from the container and injects the VM into the DataContext. David Hill I believe has a post on this.
December 7th, 2009 at 18:40
Thanks Glenn for the tip, I was looking at it in order to enable blendability and see sample data in design time, this one was the reason for which I was trying the PartCreator approach in the post
I’ll look at the attached behavior
December 13th, 2009 at 22:32
[...] Part 3: Part Creator and Creation Policy [...]
January 7th, 2010 at 01:19
[...] Part 3: Part Creator and Creation Policy [...]