Series recap:
In the final part of this series, I will show a dynamically loaded module (using PRISM) that takes full advantage of MEF.
Here is a preview of the final product, illustrating the different modules and areas I have pulled together to demonstrate (click for a full resolution view):
Download the Source for this Example
Why even bother with dynamic modules? Dynamic module loading can be a powerful way to build scalable (and more stable) applications in Silverlight. By creating dynamic modules, you ensure the user only loads what they need, when they need it. The dynamic module only comes into play when the user demands a feature that requires the module.
Before we dive into the new MEF-based module, let’s break down a few best practices when using dynamically loaded modules:
When everything comes together as planned, you can scan traffic with a tool like Fiddler to see what happens. Take a look at this example. Here, you can clearly see the satellite modules are loaded dynamically. In fact, the MEF module, which displays a list and dynamically displays a child view, weighs in at only 5,000 bytes!
Click here to view the Fiddler snapshot
I started by adding a new Silverlight Application and calling it MEFModule.
The MEF ViewModel
The MEF view model looks like this:
[Export] public class MoreStuffViewModel : IPartImportsSatisfiedNotification { private IService _service; [Import] public IService Service { get { return _service; } set { _service = value; if (_service != null) { _service.GetMoreStuff(_ServiceLoaded); } } } [ImportMany("MoreStuff",AllowRecomposition=true)] public List<string> ImportedStuff { get; set; } [Import] public IRegionManager RegionManager { get; set; } public DelegateCommand<object> DynamicViewCommand { get; set; } [Import("DynamicView")] public object DynamicView { get; set; } private ObservableCollection<string> _listOfMoreStuff; public MoreStuffViewModel() { // initialize all lists _listOfMoreStuff = new ObservableCollection<string>(); DynamicViewCommand = new DelegateCommand<object>(o => { RegionManager.RegisterViewWithRegion("MainRegion", () => DynamicView); }); } private void _ServiceLoaded(List<string> values) { foreach (string value in values) { _listOfMoreStuff.Add(value); } } public ObservableCollection<string> ListOfMoreStuff { get { return _listOfMoreStuff; } set { _listOfMoreStuff = value; } } #region IPartImportsSatisfiedNotification Members public void OnImportsSatisfied() { foreach (string importedValue in ImportedStuff) { _listOfMoreStuff.Add(importedValue); } } #endregion }
I’ve purposefully loaded this view model with tons of goodies to help understand and take advantage of MEF to its fullest. You’ll notice two things right away about the view model: it is exported using the Export
attribute, and it implements an interface called IPartImportsSatisfiedNotification
. When you implement this interface, MEF will automatically call OnImportsSatisfied
, allowing you to react to the new imports.
You’ll notice I have a collection called ImportedStuff
that imports a contract with a magic string (tip: in a production project this would probably be a type or an enumeration or at least a static class with a constant to allow for type checking) called MoreStuff. We’ll give this collection what it needs somewhere else, for now it is simply waiting for imports and when those imports are satisfied, we merge them into our master ListOfMoreStuff
collection.
We also reference IService
. If you remember, when we set that up back in part 1, we went ahead and added an Export
tag. Here, we import it. Notice that on the setter, when the import happens, I go ahead and call the GetMoreStuff
method, which returns me the Spanish numbers. When these are loaded, we merge them into our master ListOfMoreStuff
. So the list will contain the results of the service call and any MoreStuff imports we may find.
We also want to dynamically display another view, but we don’t know what that view is yet. Remember in part 2 I explicitly set the export value of IRegionManager
using Unity to resolve it? This is where we will import it!
The DynamicViewCommand
gives us a command to bind to in order to show that view. The view gets imported with another magic string (again, just stating I know we don’t like them, but they are there for the sake of brevity in this example only) called DynamicView
. In the constructor for the view model, we bind the command to a call to RegisterViewWithRegion
and pass in the dynamic view.
This demonstrates how powerful MEF really is: we are able to specify an action to dynamically show a view here in the view model without any prior knowledge of where the view is or even what it is composed of!
The rest of the view model code simply initializes lists, combines them, etc. We’ve got our view model in place. How about some views that use it?
The MEF Views
In the views folder, I created two views. The first or “main” view is simply called MoreStuffView
and it binds to the ListOfMoreStuff
collection as well as the dynamic view command:
<ListBox ItemsSource="{Binding ListOfMoreStuff}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Button Grid.Column="1" cal:Click.Command="{Binding DynamicViewCommand}" Content="Add View"/>
The code behind requires two pieces: first, we need to import the view model and bind it:
[Import] public MoreStuffViewModel ViewModel { get { return (MoreStuffViewModel)LayoutRoot.DataContext; } set { LayoutRoot.DataContext = value; } }
Next, we need to call our friend, the PartInitializer
class, to satisfy all of the imports in the constructor:
public MoreStuffView() { InitializeComponent(); PartInitializer.SatisfyImports(this); }
And that’s it … all of the services, exports, etc will be wired in elsewhere. I created a second view called DynamicView
. This view simply contains a text block that indicates it was dynamically loaded. Remember how we had our “magic string” import for a view in the view model? Here, we will export the dynamic view in the code behind. There is only one change to the auto-generated code behind file, and that is to add the Export
tag:
[Export("DynamicView")] public partial class DynamicView : UserControl { public DynamicView() { InitializeComponent(); } }
That’s it for the view model and the views!
Providing Exports
The exports can obviously be supplied in a variety of ways. For this example, I simply created a class and exported a few values to demonstrate that the imports were working and merging with the main list:
public class MoreStuffExports { [Export("MoreStuff")] public string Item1 { get { return "MEF Export 1"; } } [Export("MoreStuff")] public string Item2 { get { return "MEF Export 2"; } } }
The MEF Module Initializer
Now it’s time to wire everything together. There is actually almost nothing to the module initializer class. Because we base it on the PartModule
we defined in the last post, the MEF-specific actions happen as part of the base class. In this class, we simply register the main view:
public class MEFInit : PartModule { IRegionManager _regionManager; public MEFInit(IRegionManager regionManager) { _regionManager = regionManager; } #region IModule Members public override void Initialize() { base.Initialize(); // gotta call base for the MEF magic to happen _regionManager.RegisterViewWithRegion("MainRegion", typeof(MoreStuffView)); } #endregion }
That’s it!
Conclusion
The goal of this this small series is to demonstrate how well PRISM and MEF work together, and how accessible modular and extensible applications can be in Silverlight 3. You’ve learned several ways to marry the view model to the view using different types of dependency injection containers and patterns. You’ve also seen how to take advantage of dynamically loaded modules to create application extensions that have an extremely small footprint but can easily integrate with the flexibility provided by both Unity and MEF in the context of PRISM.
Download the Source Code for this example
Cloud management is difficult to do manually, especially if you work with multiple cloud…
Azure’s scalable infrastructure is often cited as one of the primary reasons why it's the…
https://www.youtube.com/watch?v=wDzCN0d8SeA Watch our "Unlocking the Power of AI in your Software Development Life Cycle (SDLC)"…
FinOps is a strategic approach to managing cloud costs. It combines financial management best practices…
Using Kubernetes with Azure combines the power of Kubernetes container orchestration and the cloud capabilities…
In the intricate landscape of modern business, compliance is both a cornerstone of operational integrity…
View Comments
Looks like your link to part 3 on this page is missing the href
I am looking for a good working example of MEF/Prism with Silverlight. I downloaded your example. PRISM, MEF, and MVVM Part 3 of 3: Dynamic MEF Modules in PRISM
It compiles and displays the startup page fine, but clicking either button causes an exception. The exception window displayed did not allow me to copy the exception. Here is the start of the exception.
An unhandled exception ('Unhandled Error in Silverlight Application Code: 4004 Category: ManagedRuntimeError Message: Microsoft.Practices.Composite.Modularity.ModuleTypeLoadingException: Failed to load type for module MEFModule. Error was: An exception occurred during a WebClient request. ---> System.Net.WebException: An exception occurred during a WebClient request. --> System.NotSupportedException: The URI prefix is not recognized a System.Net.WebRequest.Create(Uri requestUri) at System.Net.WebClient.GetWebRequest(Uri address) at System.Net.WebClient.OpenReadAsync(Uri address, Object userToken) --- End of inner exception stack trace ---
etcetera .....
I am using Prism 4/Silverlight 5 with the latest version of MEF on Windows 8 Professional.
Any ideas??
Thanks...
could you provide valid link to the source code?