MEF插件式开发

一、MEF 简介

1、 Managed Extensibility Framework简称MEF,是WPF中的一种插件式开发的框架。其开发程序的主要优点如下:

  • 易于将复杂程序进行拆分成不同的功能模块,然后进行多团队的协作。将各个功能编译成dll的形式提供给主程序,由主程序进行统一加载。
  • 便于程序的后期扩展,在后期需要添加新功能时,只需要提供对应的dll即可,主程序无需进行大的改动。
  • 不同模块间的功能相对独立,降低程序的耦合性,使程序易于维护。

2、MEF 的使用需要引用System.ComponentModel.Composition,该dll提供了MEF开发的核心功能。

3、MEF程序的组成部分:

  • 主程序:一般为一个WPF可执行应用程序,用来提供整个程序的框架,并加载各个功能模块所编译生成的dll程序集。
  • 接口程序:一般为类库项目(即Class Library),编译生成dll文件。主要用来定义主程序与各个Plugin插件程序之间的接口,只有定义好这些接口才能保证主程序正确加载各个Plugin
  • 插件程序:一般为WPF User Control Library,即各个独立的功能模块,编译生成dll文件,被主程序加载使用。

二、MEF程序创建流程

所有项目均位于解决方案MEF_Project

1、创建WPF应用主程序

1.1 主程序为WPF Application
在这里插入图片描述
1.2 后续接口项目和各个Plugin项目编译完成后,需要再完善主程序以加载各个插件

2、创建接口项目MyInterface

在这里插入图片描述
2.1 接口项目中,接口类型的关键字为interface,在接口中只能声明而不能有具体的实现,具体的实现需要在其派生类中来进行。

2.2 该项目中定义如下接口:

namespace MyInterface
{
    /// <summary>
    /// 定义接口类型
    /// </summary>
    public interface IMyInterface
    {
        string GetPluginName();
        int GetPluginId();
    }
}

2.3 因为后续的Plugin项目需要引用该接口生成的dll文件,所以需要先对该接口项目进行编译,以生成对应的dll文件,在此编译生成 MyInterface.dll 文件。

3、创建插件项目PluginA

该项目为UserControl类型,如下图所示
在这里插入图片描述
3.1XAML文件进行设计,如下所示:

<UserControl x:Class="PluginA.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PluginA"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <StackPanel>
        <Label x:Name="labelA" Content="Pugin A Page" FontSize="40" HorizontalAlignment="Center"/>
    </StackPanel>
</UserControl>

3.2 .cs文件中,添加两个对应的dllReferences,并引用到命名空间中
(1)、在References中添加MEF对应dllSystem.ComponentModel.Composition;,并引用到命名空间中,如下图:
在这里插入图片描述
(2)、在References中添加接口项目编译生成的dllMyInterface.dll,并引用到命名空间中,如下图:
在这里插入图片描述
3.3 导入并实现该接口,代码如下:

using System.Windows.Controls;
using System.ComponentModel.Composition;
using MyInterface;

namespace PluginA
{
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>

    // 导入该接口
    [Export(typeof(IMyInterface))]
    public partial class UserControl1 : UserControl, IMyInterface
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        //对接口IMyInterface的实现
        public int GetPluginId()
        {
            return 0;
        }

        public string GetPluginName()
        {
            return "This is Plugin A";
        }
    }
}

3.3 编译生成对应的PluginA.dll文件

【以同样的方式创建PluginB


4、完善主程序MainProgram,加载上面编译生成的各个Plugin插件

4.1 设计主程序的UI,对应的MainWindow.xaml文件如下:

<Window x:Class="MainProgram.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MainProgram"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <!--左侧为ListView栏-->
        <ListView x:Name="ItemsList" Grid.Column="0" Background="Bisque"/>
        <!--中间为分割条-->
        <GridSplitter Grid.Column="1" Width="6" VerticalAlignment="Stretch" HorizontalAlignment="Center" ShowsPreview="False"/>
        <!--右侧显示加载的各个Plugin的内容-->
        <Frame x:Name="frameContent" Grid.Column="2"/>
    </Grid>
</Window>

在这里插入图片描述

4.2MainWindow.xaml.cs中添加对应的dll文件
(1)、在References中添加MEF对应dllSystem.ComponentModel.Composition;,并引用到命名空间中。
(2)、在References中添加接口项目编译生成的dllMyInterface.dll,并引用到命名空间中。

4.3 在主程序中解析、加载对应Plugin程序集,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using MyInterface;

namespace MainProgram
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private IEnumerable<IMyInterface> myPlugins;
        public MainWindow()
        {
            InitializeComponent();

            //new DirectoryCatalog 的默认加载目录为:该程序的exe文件目录下,为Debug目录或Release目录
            var catalog = new DirectoryCatalog("../../MyPlugins");
            var container = new CompositionContainer(catalog);
            myPlugins = container.GetExportedValues<IMyInterface>();

            foreach (var plg in myPlugins)
            {
                /*该方式只是简单的加载显示,但没有任何事件,点击也无效
                 * string name = plg.GetPluginName();
                this.ItemsList.Items.Add(new TabItem() { Header = name, Content = plg });*/

                Button btn = new Button();
                btn.FontSize = 20;
                btn.FontFamily = new FontFamily("Times New Roman");
                btn.HorizontalAlignment = HorizontalAlignment.Center;
                btn.Content = plg.GetPluginName();
                btn.Tag = plg.GetPluginId();
                btn.Click += Btn_Clicked;
                ItemsList.Items.Add(btn);
            }
        }

        private void Btn_Clicked(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            int id = Convert.ToInt32(btn.Tag); //Tag为object类型,需要显示的转换成int类型
            frameContent.Content = myPlugins.ElementAt(id);

        }
    }
}

4.4 在主程序目录下创建文件夹,存放各个Plugin编译生成的dll文件,以被主程序加载,整体的文件结构如下所示:

  • MainProgram:为主程序项目目录
  • MyInterface:为接口程序项目目录
  • PluginA:为插件A项目目录
  • PluginB:为插件B项目目录
    在这里插入图片描述
    在这里插入图片描述

4.5 运行结果如下:
在这里插入图片描述


参考资料:
[1] Managed Extensibility Framework
[2] System.ComponentModel.Composition Namespace

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 对于“c”的问题,需要进一步明确问题的具体内容。在数学中,“c”可能代表一些常数或系数,例如在一元一次方程中,c通常代表常数项;在求导中,c则代表常数函数的导数为零;在复数中,c则常用于表示实部。 在计算机领域中,C语言是一种广泛使用的编程语言,它具有高效、可移植、简洁等特点,成为了操作系统、网络、嵌入系统等方面的主流开发语言。同时,“c”也是C语言代码中的一个标记符号,通常用于表示变量或函数名。 除此之外,在其他领域中,“c”也可能有不同的含义和用法。例如在物理学中,c代表光速常数;在化学中,c可能代表一种化合物的命名方等。 综上所述,对于“c”的问题需要明确具体的语境和意义,才能准确回答。 ### 回答2: C是计算机科学中的一种编程语言,也是一种很常见的编程语言。它由美国贝尔实验室的丹尼斯·里奇在20世纪70年代初开发而成。 C语言具有简洁、高效的特点,被广泛应用于系统软件和应用软件开发中。C语言通过控制硬件资源和底层操作系统功能,提供了对计算机底层的直接访问能力,因此在开发操作系统、嵌入系统和驱动程序等方面有着广泛的应用。 C语言的语法简洁明了,易于学习和理解。它具有结构化的特点,支持模块化的程序设计,程序可以分成多个独立的、可复用的模块,方便代码的维护和扩展。C语言还提供了丰富的库函数,开发者可以利用这些库函数快速实现各种功能。 C语言是编写高效代码的重要工具。由于C语言的语法和特性与机器语言非常接近,因此编写的程序在执行效率上非常高。C语言还可以直接调用汇编语言,利用汇编语言进行优化,进一步提高了程序的性能。 总之,C语言是一种重要的编程语言,广泛应用于计算机科学领域。其简洁、高效、灵活的特点使得它成为开发各种软件和系统的首选语言之一。对于想要从事编程领域的人来说,掌握C语言是一个重要的基础,可以帮助他们理解底层原理,提高程序的执行效率,实现各种功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值