MatthiasG shows a way to define modules in MEF. Please note: the view itself does not implement IModule. However, the interesting part of using MEF with PRISM is how to import modules into the user interface at startup.
I can explain the system in principle here, but it may point you in the right direction. There are always many approaches to everything, but this is what I understood as the best practice and that I made a very good experience:
Bootstrap
As with Prism and Unity, it all starts with Bootstrapper, which is obtained from MefBootstrapper at Microsoft.Practices.Prism.MefExtensions . The bootloader installs the MEF container and thus imports all types, including services, views, ViewModels and models.
Export of views (modules)
This is the part referenced by MatthiasG. My practice is the following structure for GUI modules:
The model exports itself as a specific type (it can also be an interface, see MatthiasG) using the [Export(typeof(MyModel)] attribute. Check with [PartCreationPolicy(CreationPolicy.Shared)] to indicate that only one instance is created (single user behavior).
ViewModel exports itself as its specific type in the same way as a model, and imports the model through constructor injection:
[ImportingConstructor] public class MyViewModel (model MyModel) {_model = model; }
View imports ViewModel using the constructor insert, just as ViewModel imports Model
And now this is important: The View exports itself with a specific attribute, which is obtained from the attribute 'standard' [Export] . Here is an example:
[ViewExport(RegionName = RegionNames.DataStorageRegion)] public partial class DataStorageView { [ImportingConstructor] public DataStorageView(DataStorageViewModel viewModel) { InitializeComponent(); DataContext = viewModel; } }
[ViewExport] attribute
The [ViewExport] attribute has two functions: since it is derived from the [Export] attribute, it tells the MEF container to import the view. Like what? This is hidden in it by defintion: the constructor signature looks like this:
public ViewExportAttribute() : base(typeof(UserControl)) {}
By calling the [Export] constructor of type UserControl , each view is registered as a UserControl in the MEF container.
Secondly, it defines the RegionName property, which will later be used to determine in which area of โโthe shell UI the view should be connected. The RegionName property is the only member of the IViewRegionRegistration interface. Attribute Class:
Import Views
Now, the last important part of the system is the behavior that you attach to areas of your shell: AutoPopulateExportedViews . This imports your entire module from the MEF container with this line:
[ImportMany] private Lazy<UserControl, IViewRegionRegistration>[] _registeredViews;
This imports all types registered as a UserControl from the container if they have a metadata attribute that implements IViewRegionRegistration . Since your [ViewExport] attribute does this, it means that you import every type marked with the [ViewExport(...)] sign.
The last step is to connect the views to the areas that bahvior does in it. OnAttach() property:
Pay attention to .Where(v => v.Metadata.RegionName == Region.Name) . This uses the RegionName property of the attribute to get only those views that are exported for a specific region to which you are binding behavior.
The behavior binds to areas of your shell in the bootloader:
protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors() { ViewModelInjectionBehavior.RegionsToAttachTo.Add(RegionNames.ElementViewRegion); var behaviorFactory = base.ConfigureDefaultRegionBehaviors(); behaviorFactory.AddIfMissing("AutoPopulateExportedViewsBehavior", typeof(AutoPopulateExportedViewsBehavior)); }
Let's start with the full circle. I hope you get an idea of โโhow everything happens with MEF and PRISM.
And, if you're still not bored: that's fine:
Mike Tautey screencast