65.9K
CodeProject 正在变化。 阅读更多。
Home

个人集成平台

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2013年10月23日

CPOL

2分钟阅读

viewsIcon

16022

downloadIcon

210

一个基于 Prism 思想的 MVVM 平台。

介绍 

我最近学习了 Prism,我认为这个框架的主要目的是实现松耦合。所以我决定构建一个使用 Prism 思想的个人集成平台。而且我可以使用这个平台来集成我过去创建的应用程序。

背景

该平台基于 'MEF','WPF MVVM 模式' 和 'Prism 思想' 技术。对于个人指示,我使用了 Prism 的思想,并对 Prism 中的组件进行了轻量级实现,例如 'ServiceLocator','Bootstrapper' 和 'Modularity'。而且我封装了 'WPF MVVM 模式' 的基本支持。

将来我会更新 Prism 的实现和 MVVM 的基本支持。

架构

我的系统架构如下:

 

a. Personal.Component

作为一个基本组件,我参考了 Prism 的思想,并实现了 Prism 的几个组件,包括 'Bootstrapper','ServiceLocator' 和 'Modularity',它们使用 MEF 架构。所有这些组件都是轻量级实现。

b. Personal.Presentation

作为一个基本组件,我封装了 WPF MVVM 模式,包括 'ViewModel','RelayCommand' 和 FrameworkElement 的一些行为。我会不断更新这个组件。

c. 集成实用工具

此组件支持集成的业务。集成的数据结构和服务在此组件中定义。

d. 个人集成平台

此组件是在桌面上运行的 WPF Shell。

e. NotifyIconWpf

这是一个第三方应用程序,用于在 WPF 中实现托盘图标。我把它拿来用于我的 Shell。

f. 子系统

子系统是我平台中的一个定义。它指示可以集成到我的平台中的特定功能模块。我已经将关闭子系统集成到平台中,其目的是退出应用程序。

集成

我使用 MEF 架构而不是以前的 ADD-IN 架构。而且我认为 MEF 比 ADD-IN 机制更简单。

我参考 Prism 并继续使用 IModule 作为子系统。

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

该顺序是对模块进行排序以进行显示。

MEF 架构用于从程序集或目录扫描模块。我在应用程序的配置中定义扫描模式。以下是模块扫描器接口和实现。

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
}

还有一个 ModuleInitializer 负责扫描模块和初始化模块。

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
}

对于特定的子系统,它应该做的是实现特定的 IModule 并在模块上方添加 ExportAttributeExportAttribute 在 MEF 架构中定义。您应该引用 'System.Component.Composition' 程序集。

[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 支持

对于 MVVM 支持,我现在已经实现了 'ViewModel' 和 'RelayCommand'。将来我会支持更多 MVVM 组件。

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);
    }
}

运行结果

我已经实现了一个关闭模块和一个用于测试的模拟模块。以下是运行结果。

兴趣点 

在 Prism 的这种实践中,我选择了 WPF 编程,因为我的工作是系统集成。我无法接触应用程序开发。所以我练习这个是为了好玩,并且我更多地了解了这个框架。

历史

我会不断更新所有组件。

© . All rights reserved.