Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Personal Integration Platform

0.00/5 (No votes)
24 Oct 2013 1  
A MVVM platform based on the thought of Prism.

Introduction 

I learned the Prism recently, and I believe the main purpose of this framework is to implement loose coupling. So I made my decision to build a personal integration platform which uses the thought of Prism. And I can use the platform to integrate my applications created in the past.

Background

This platform is based on the technic of 'MEF', 'WPF MVVM pattern' , and 'the thought of Prism'. For personal indication, I used the thought of Prism, and did a lightweight implementation of components in Prism, such as 'ServiceLocator', 'Bootstrapper', and 'Modularity'. And I encapsulated the base support for the 'WPF MVVM pattern'.

I will update for the Prism implementation and base support for MVVM in the future.

Architecture  

My system architecture is as below:

 

a. Personal.Component

As a basic component, I refer to the thought of Prism, and I implement several components of Prism, including 'Bootstrapper', 'ServiceLocator', and 'Modularity which use MEF architecture. All these components are lightweight implementations.

b. Personal.Presentation

As a basic component, I encapsulate the WPF MVVM pattern, including 'ViewModel', 'RelayCommand', and some behavior for the FrameworkElement. I will update this component continually.

c. Integration Utilities

This component supports the business of integration. The data structure and service for the integration are defined in this component.

d. Personal Integration Platform

This component is the WPF shell running in the desktop.

e. NotifyIconWpf

This is a third party application implementing a tray icon in WPF. I took it up for my shell.

f. Sub-System

Sub-system is a definition in my platform. It indicates a particular function module which can integrate into my platform. I have integrated the shutdown sub-system into the platform whose purpose is to exit the application.

Integration 

I use MEF architecture instead of the former ADD-IN architecture. And I think MEF is simpler than the ADD-IN mechanism.

I refer to Prism and continue to use IModule for the sub-system.

public interface IModule
{
    int Order { get; }
    void Initialize();
}

The order is to sort the modules to display.

MEF architecture is used to scan the Modules from the assembly or directory. I define the scan mode in the configuration of the application. Below is the Module scanner interface and the implementation.

public interface IModuleScanner
{
    void SetAssemblies(params Assembly[] assemblies);
    void SetDirectories(params string[] directories);
    IEnumerable<IModule> GetModules();
}

public enum ScanMode
{
    Assembly    = 0,
    Directory   = 1,
    Mixed       = 2
};

public class MEFModuleScanner : IModuleScanner
{
    [ImportMany]
    private IEnumerable<IModule> _moudles;
    private AggregateCatalog _aggregateCatalog = new AggregateCatalog();

    #region IModuleScaner Members

    public void SetAssemblies(params Assembly[] assemblies)
    {
        if (assemblies != null)
        {
            foreach (var assembly in assemblies)
            {
                _aggregateCatalog.Catalogs.Add(new AssemblyCatalog(assembly));
            }
        }
    }

    public void SetDirectories(params string[] directories)
    {
        if (directories != null)
        {
            foreach (var directory in directories)
            {
                if (Directory.Exists(directory))
                {
                    _aggregateCatalog.Catalogs.Add(new DirectoryCatalog(directory));
                }
            }
        }
    }

    public IEnumerable<IModule> GetModules()
    {
        CompositionContainer container = new CompositionContainer(_aggregateCatalog);
        try
        {
            container.ComposeParts(this);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.StackTrace);
        }
        return _moudles;
    }

    #endregion
}

And there is a ModuleInitializer that takes charge of scanning the modules and initializing the modules.

public class ModulesInitializer
{
    private IEnumerable<IModuleScanner> _scanners;
    private IEnumerable<IModule> _modules;

    public ModulesInitializer(IEnumerable<IModuleScanner> scanners)
    {
        _scanners = scanners;
    }

    public ModulesInitializeMode Mode { get; set; }
    public void SetScanAssemblies(Assembly[] assemblies)
    {
        if (_scanners != null)
        {
            foreach (var scanner in _scanners)
            {
                scanner.SetAssemblies(assemblies);
            }
        }
    }
    public void SetScanDirectories(string[] directories)
    {
        if (_scanners != null)
        {
            foreach (var scanner in _scanners)
            {
                scanner.SetDirectories(directories);
            }
        }
    }
    public void Scan()
    {
        List<IModule> moduleList=new List<IModule>();
        foreach (var scanner in _scanners)
        {
            var modules = scanner.GetModules();
            moduleList.AddRange(modules);
        }
        _modules = moduleList;
    }
    public void Initialize()
    {
        foreach (var module in _modules)
        {
            module.Initialize();
        }
    }
}

public enum ModulesInitializeMode
{
    Assemblies  = 0,
    Directories = 1,
    Mixed       = 2
}

For the particular sub-system, what it should do is implement the particular IModule and add the ExportAttribute above the module. The ExportAttribute is defined in the MEF architecture. You should reference the 'System.Component.Composition' assembly.

[Export(typeof(IModule))]
public class ShutDownModule : Module
{
    public override int Order
    {
        get { return int.MaxValue; }
    }
    protected override void Initialize(IIntegrationRepository integrationRepository)
    {
        integrationRepository.Register(new ShutDownElementViewModel());
    }
}

MVVM support 

For MVVM support, I have implemented the 'ViewModel' and 'RelayCommand' for now. I will support more components for MVVM in the future.

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class RelayCommand : ICommand
{
    readonly Action mExecute;
    readonly Func<bool> mCanExecute;

    public RelayCommand(Action execute)
        : this(execute, null)
    {
    }
    public RelayCommand(Action execute, Func<bool> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        mExecute = execute;
        mCanExecute = canExecute;
    }

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return mCanExecute == null ? true : mCanExecute();
    }
    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (mCanExecute != null)
                CommandManager.RequerySuggested += value;
        }
        remove
        {
            if (mCanExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }
    public void Execute(object parameter)
    {
        mExecute();
    }
}

public class RelayCommand<T> : ICommand
{
    readonly Action<T> mExecute = null;
    readonly Predicate<T> mCanExecute = null;

    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (mCanExecute != null)
                CommandManager.RequerySuggested += value;
        }
        remove
        {
            if (mCanExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }

    public RelayCommand(Action<T> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        mExecute = execute;
        mCanExecute = canExecute;
    }

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return mCanExecute == null ? true : mCanExecute((T)parameter);
    }
    public void Execute(object parameter)
    {
        mExecute((T)parameter);
    }
}

The result of Run 

I have implemented a shutdown module and a mock module for testing. Below is the result of running.

Points of Interest 

In this practice of Prism, I picked up WPF programming because my work is system-integration; I cannot touch application development. So I practiced this for a fun, and I learned more about the framework for my fun.

History

I will update all the components continually.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here