Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

Migrate from Basic to MVVM and MEF Composable Patterns for a Silverlight Application - Part 3

, 3 May 2012 CPOL
The article series shows how to upgrade a Silverlight application having basic patterns to the MVVM and MEF composable patterns with easy approaches and detailed coding explanations.
MigrateToMvvmMef-Part1_Src.zip
MigrateToMvvmMef-Part1_Src
ProductApp.Common
Bin
Release
Constants
ModuleServices
obj
ProductApp.Common.csproj.user
Properties
ProductApp.Main
Assets
Bin
Release
obj
ProductApp.Main.csproj.user
Properties
Views
ProductApp.suo
ProductApp.Views
Assets
Bin
Release
obj
ProductApp.Views.csproj.user
Properties
ProductApp.Web
bin
ClientBin
obj
ProductApp.Web.csproj.user
Properties
ProductRiaLib
ProductRiaLib.Web
App_Data
bin
Debug
EntityFramework.dll
Microsoft.ServiceModel.DomainServices.EntityFramework.dll
Release
Models
obj
ProductRiaLib.Web.csproj.user
Properties
Services
Bin
Release
obj
ProductRiaLib.csproj.user
Properties
MigrateToMvvmMef-Part2_Src.zip
MigrateToMvvmMef-Part2_Src
ProductApp.Common
Bin
Release
Constants
EventArguments
Models
ModuleServices
obj
ProductApp.Common.csproj.user
Properties
ProductApp.Main
Assets
Bin
Release
obj
ProductApp.Main.csproj.user
Properties
ViewModels
Views
ProductApp.Models
Bin
Release
obj
ProductApp.Models.csproj.user
Properties
ProductApp.suo
ProductApp.ViewModels
Bin
Release
obj
ProductApp.ViewModels.csproj.user
Properties
ProductApp.Views
Assets
Bin
Release
obj
ProductApp.Views.csproj.user
Properties
ProductApp.Web
bin
ClientBin
obj
ProductApp.Web.csproj.user
Properties
ProductRiaLib
ProductRiaLib.Web
App_Data
bin
Debug
EntityFramework.dll
Microsoft.ServiceModel.DomainServices.EntityFramework.dll
Release
Models
obj
ProductRiaLib.Web.csproj.user
Properties
Services
Bin
Release
obj
ProductRiaLib.csproj.user
Properties
_Assemblies
GalaSoft.MvvmLight.SL5.dll
System.Windows.Interactivity.dll
MigrateToMvvmMef-Part3_Src.zip
MigrateToMvvmMef-Part3_Src
AnotherXap.Models
AnotherXap.Models.csproj.user
Bin
Release
obj
Properties
AnotherXap.ViewModels
AnotherXap.ViewModels.csproj.user
Bin
Release
obj
Properties
AnotherXap.Views
AnotherXap.Views.csproj.user
Assets
Bin
Release
obj
Properties
ProductApp.Common
Bin
Release
Constants
EventArguments
Models
ModuleServices
obj
ProductApp.Common.csproj.user
Properties
SaveState
ProductApp.Main
Assets
Bin
Release
Models
obj
ProductApp.Main.csproj.user
Properties
ViewModels
Views
ProductApp.Models
Bin
Release
obj
ProductApp.Models.csproj.user
Properties
ProductApp.suo
ProductApp.ViewModels
Bin
Release
obj
ProductApp.ViewModels.csproj.user
Properties
ProductApp.Views
Assets
Bin
Release
obj
ProductApp.Views.csproj.user
Properties
ProductApp.Web
bin
ClientBin
obj
ProductApp.Web.csproj.user
Properties
ProductRiaLib
ProductRiaLib.Web
App_Data
bin
Debug
EntityFramework.dll
Microsoft.ServiceModel.DomainServices.EntityFramework.dll
Release
Models
obj
ProductRiaLib.Web.csproj.user
Properties
Services
Bin
Release
obj
ProductRiaLib.csproj.user
Properties
_Assemblies
GalaSoft.MvvmLight.SL5.dll
System.Windows.Interactivity.dll
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace ProductApp.Common
{
    public class ModuleCatalogService
    {
        // Define a catalog of the mixed type
        private static AggregateCatalog _aggregateCatalog;

        // Define the dictionary for loaded xaps
        private Dictionary<string, DeploymentCatalog> _catalogs;

        // Define the collections for storing expored modules
        private List<ExportLifetimeContext<IModule>> _contextList;
        private List<Lazy<IModule>> _lazyList;

        // Define the container
        public static CompositionContainer Container { get; private set; }

        // Expose this service instance
        public static ModuleCatalogService Instance { get; private set; }

        // Define a collection of ExportFactory object
        [ImportMany(AllowRecomposition = true)]
        public IEnumerable<ExportFactory<IModule, IModuleMetadata>> FactoryModules { get; set; }

        // Define a collection of Lazy object
        [ImportMany(AllowRecomposition = true)]
        public IEnumerable<Lazy<IModule, IModuleMetadata>> LazyModules { get; set; }

        public ModuleCatalogService()
        {
            _catalogs = new Dictionary<string, DeploymentCatalog>();
            _contextList = new List<ExportLifetimeContext<IModule>>();
            _lazyList = new List<Lazy<IModule>>();

            // Fill the imports of all parts held by this service instance 
            CompositionInitializer.SatisfyImports(this);
        }

        static ModuleCatalogService()
        {
            _aggregateCatalog = new AggregateCatalog();

            //Add an instance of catalog for xap to the Catalog collection
            _aggregateCatalog.Catalogs.Add(new DeploymentCatalog());

            //Use the aggregate catalog with the container
            Container = new CompositionContainer(_aggregateCatalog);

            // Initialize the logical composition container
            CompositionHost.Initialize(Container);

            Instance = new ModuleCatalogService();
        }

        public static void Initialize()
        {
            // Any call to this static method will call the static constructor
            // the "ModuleCatalogService()"
            // It's called firstly from the starting App.xaml.cs 
        }

        public void AddXap(string uri, Action<AsyncCompletedEventArgs> completedAction = null)
        {
            DeploymentCatalog catalog;
            if (!_catalogs.TryGetValue(uri, out catalog))
            // Run the code if the xap is not loaded (no data in the dictionary)
            {
                catalog = new DeploymentCatalog(uri);

                // Event handler registered and running for adding the xap
                catalog.DownloadCompleted += (s, e) =>
                {
                    if (e.Error == null)
                    {
                        // Add the DeploymentCatelog instance to the dictionary.
                        _catalogs.Add(uri, catalog);

                        // Add the DeploymentCatelog instance to the Catologs collection                        
                        _aggregateCatalog.Catalogs.Add(catalog);
                    }
                    else
                    {
                        throw new Exception(e.Error.Message, e.Error);
                    }
                };

                // Set the event handler and notify the caller
                if (completedAction != null)
                    catalog.DownloadCompleted += (s, e) => completedAction(e);

                // Begin to download the xap
                catalog.DownloadAsync();
            }
            else
            // Xap has been loaded previously and just notify the caller
            // to run the event handler routine
            {
                if (completedAction != null)
                {
                    AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(null, false, null);
                    completedAction(e);
                }
            }
        }

        public void RemoveXap(string uri)
        {
            DeploymentCatalog catalog;
            if (_catalogs.TryGetValue(uri, out catalog))
            {
                // Remove the DeploymentCatelog instance in the Catalogs collection                
                _aggregateCatalog.Catalogs.Remove(catalog);

                // Remove the xap from the dictionary
                _catalogs.Remove(uri);
            }
        }

        public object GetModule(string moduleId)
        {
            // An object to hole an instance of ExportLifetimeContext
            ExportLifetimeContext<IModule> context;

            // Search for the module by matching the metadata Name property
            context = FactoryModules.FirstOrDefault(
                          n => (n.Metadata.Name == moduleId)).CreateExport();

            // Cache the instance of ExportLifetimeContext to the list
            _contextList.Add(context);

            return context.Value;
        }

        public object GetModuleLazy(string moduleId)
        {
            // A Lazy object to hold the exported module 
            Lazy<IModule, IModuleMetadata> lazyModule;

            // Search for the module by matching the metadata Name property
            lazyModule = LazyModules.FirstOrDefault(n => n.Metadata.Name == moduleId);

            // Cache the instance of the Lazy to the list
            _lazyList.Add(lazyModule);

            return lazyModule.Value;
        }

        public bool ReleaseModule(IModule module)
        {
            // Set module reference back to the context            
            ExportLifetimeContext<IModule> context = 
               _contextList.FirstOrDefault(n => n.Value.Equals(module));
            if (context == null) return false;

            // Remove the module context from the collection 
            _contextList.Remove(context);

            // Calls Cleanup() in the module and then set the module null. 
            context.Dispose();
            context = null;

            return true;
        }

        public bool ReleaseModuleLazy(IModule module)
        {
            // Set module reference back to the lazyModule 
            Lazy<IModule> lazyModule = _lazyList.FirstOrDefault(n => n.Value.Equals(module));
            if (lazyModule == null) return false;

            // Remove the module lazy from the collection
            _lazyList.Remove(lazyModule);

            // No Dispose() for the Lazy object and call this method of the container
            Container.ReleaseExport(lazyModule);
            lazyModule = null;

            return true;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Shenwei Liu

United States United States
Shenwei is a software developer and architect, and has been working on business applications using Microsoft and Oracle technologies since 1996. He obtained Microsoft Certified Systems Engineer (MCSE) in 1998 and Microsoft Certified Solution Developer (MCSD) in 1999. He has experience in ASP.NET, C#, Visual Basic, Windows and Web Services, Silverlight, WPF, JavaScript/AJAX, HTML, SQL Server, and Oracle.

| Advertise | Privacy | Mobile
Web04 | 2.8.141022.2 | Last Updated 3 May 2012
Article Copyright 2012 by Shenwei Liu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid