“托管扩展性框架(Managed Extensibility Framework,简称MEF),是微软.NET框架下为提高应用和组件复用程度而推出的,用于使组件能够最大化的重用。使用MEF能够使静态编译的.NET应用程序转换为动态组合,这将是创建可扩展应用、可扩展框架和应用扩展的好途径。它将做为.NET Framework 4.0的组成部分之一发布。现在,MEF也将被包含在Silverlight 4.0中。

那么MEF是怎样工作的呢?简单分为三个步骤:

•Export (输出) •Import (输入) •Compose (组合) 简短说一下MEF的工作原理,MEF的核心包括一个catalog和一个CompositionContainer。category用于发现扩展,而container用于协调创建和梳理依赖性。每个可组合的Part提供了一个或多个Export,并且通常依赖于一个或多个外部提供的服务或Import。每个Part管理一个实例为应用程序运行。

下面我们做一个小型可扩展计算器示例来解释这三个过程

1.首先下载MEF框架包,Silverlight 4.0会自带,不过微软已经将其开源了。 http://www.codeplex.com/MEF 2.创建一个Silverlight Navigate Application ,并添加程序集引用(MEF_Beta_2\bin\SL目录下 System.ComponentModel.Composition.dll) 在项目下添加两个类文件Package.cs和PackageCatalog.cs,这两个文件在最新的MEF版本中没有提供,主要用于加载silverlight的Xap包。 这两个文件在MEF框架的Sample中提供了(MEF_Beta_2\Samples\PictureViewer\PictureViewer.Common),将这两个类的访问修饰符改为public, 添加后注意修改命名空间。 3.修改Home.cs 类

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel.Composition; using System.ComponentModel;

namespace MefDemo {     //用于更新界面的委托     public delegate void OperateHandler(IOperate Op);

/// <summary>     /// 运算器接口     /// </summary>     public interface IOperate     {         double Op(double left, double right);         string Symbol { set; get; }         string Label { get; set; }     }

/// <summary>     /// 加法运算器     /// </summary>     [Export(typeof(IOperate))]     public class AddButton : Button, IOperate     {         [Import("AddButtonContract",AllowRecomposition = true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("AddSybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left + right;         }

#endregion

public AddButton()         {             this.Click += (s, e) => ClickAction(this);         }     }

/// <summary>     /// 减法运算器     /// </summary>     [Export(typeof(IOperate))]     public class SubButton : Button, IOperate     {         [Import("SubButtonContract",AllowRecomposition=true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("SubSybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left - right;         }

#endregion

public SubButton()         {             this.Click += (s, e) => ClickAction(this);         }     }

/// <summary>     /// 为每个运算器的属性提供值     /// </summary>     public class ComponentAttributeProvider     {         [Export("AddButtonContract")]         public string AddLabel  { get { return "Add"; } }         [Export("AddSybomContract")]         public string AddSymbol { get { return "+"; } }         [Export("SubButtonContract")]         public string SubLabel  { get { return "Sub"; } }         [Export("SubSybomContract")]         public string SubSymbol { get { return "-"; } }     } } 4.修改 Home.xaml

代码

<navigation:Page x:Class="MefDemo.Home"     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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"     mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"     Title="Home"     Style="{StaticResource PageStyle}">

<navigation:Page.Resources>         <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">             <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"/>         </ItemsPanelTemplate>     </navigation:Page.Resources>

<Grid x:Name="LayoutRoot">         <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource PageScrollViewerStyle}">

<StackPanel x:Name="ContentStackPanel" Background="Black">                 <StackPanel   Orientation="Horizontal" Width="455" Height="89" Margin="91,0,91,-30">                     <TextBox x:Name="LeftNum" HorizontalAlignment="Left"   VerticalAlignment="Center" Width="83" TextWrapping="Wrap"/>                     <TextBlock x:Name="Symbol" Width="62" Text="+" TextWrapping="Wrap" FontSize="24" Foreground="#FFF80606" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Left"/>                     <TextBox x:Name="RightNum" HorizontalAlignment="Left"   VerticalAlignment="Center" Width="78" TextWrapping="Wrap"/>                     <TextBlock Width="64" Text="=" TextWrapping="Wrap" Foreground="#FFF20808" FontSize="21.333" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Left"/>                     <TextBox x:Name="Result" HorizontalAlignment="Left"   VerticalAlignment="Center" Width="146" TextWrapping="Wrap"/>                 </StackPanel>                 <ListBox x:Name="operateList"  ItemsSource="{Binding}" ItemsPanel="{StaticResource ItemsPanelTemplate1}" Height="99" Background="{x:Null}" BorderBrush="{x:Null}"/>         <Button x:Name="DynamicLoadButton" Height="40" Width="196" Content="DynamicLoadOperate"/>             </StackPanel>         </ScrollViewer>     </Grid>

</navigation:Page>

5.新建类 OperatorComponent.cs

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel.Composition; using System.ComponentModel;

namespace MefDemo {     //用于更新界面的委托     public delegate void OperateHandler(IOperate Op);

/// <summary>     /// 运算器接口     /// </summary>     public interface IOperate     {         double Op(double left, double right);         string Symbol { set; get; }         string Label { get; set; }     }

/// <summary>     /// 加法运算器     /// </summary>     [Export(typeof(IOperate))]     public class AddButton : Button, IOperate     {         [Import("AddButtonContract",AllowRecomposition = true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("AddSybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left + right;         }

#endregion

public AddButton()         {             this.Click += (s, e) => ClickAction(this);         }     }

/// <summary>     /// 减法运算器     /// </summary>     [Export(typeof(IOperate))]     public class SubButton : Button, IOperate     {         [Import("SubButtonContract",AllowRecomposition=true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("SubSybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left - right;         }

#endregion

public SubButton()         {             this.Click += (s, e) => ClickAction(this);         }     }

/// <summary>     /// 为每个运算器的属性提供值     /// </summary>     public class ComponentAttributeProvider     {         [Export("AddButtonContract")]         public string AddLabel  { get { return "Add"; } }         [Export("AddSybomContract")]         public string AddSymbol { get { return "+"; } }         [Export("SubButtonContract")]         public string SubLabel  { get { return "Sub"; } }         [Export("SubSybomContract")]         public string SubSymbol { get { return "-"; } }     } }

6.运行。 这样就构建了一个简单的运算器,其中的Export、Import就像一个个管道一样相互连接。

7.按照这样的设计,我们想要对其进行扩展,就必须把接口分离。新建一个Silverlight ClassLibrary Project(Named ContractLibrary),这个Library用来封装所有的扩展接口,定义Import/Export契约。 现在把原项目中的OperatorComponent.cs 类中的接口迁移到Library项目中,新建类文件OperateContract.cs 。

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes;

namespace ContractLibrary {     public delegate void OperateHandler(IOperate Op);

/// <summary>     /// 运算器接口     /// </summary>     public interface IOperate     {         double Op(double left, double right);         string Symbol { set; get; }         string Label { get; set; }     } } 编译通过后在Silverlight主工程(MefDemo)中添加对ContractLibrary项目的引用 8.再新建一个Silverlight ClassLibrary Project (Named StaticExtension),,这个工程就是我们用来静态扩展的DLL。 a). 在工程下新建我们的运算器类,AddButton.cs , SubButton.cs.(代码不变). b). 但注意要添加对ContractLibrary项目的引用和MEF的框架集引用) 。 c). 添加全局属性配置类(ComponentConfiguration.cs) d). 删除主工程中的ComponetOperater.cs. e). 添加对StaticExtension的引用.

9.OK,这样我们就可以任意扩展运算器,添加更多的扩展运算了。

10.那么下面是添加一个新的乘法运算所要做的工作。 在StaticExtension中添加新类 Multiply.cs

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel.Composition; using ContractLibrary;

namespace StaticExtension {     /// <summary>     /// 乘法运算器     /// </summary>     [Export(typeof(IOperate))]     public class MultiplyButton : Button, IOperate     {         [Import("MultiplyButtonContract", AllowRecomposition = true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("MultiplySybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left * right;         }

#endregion

public MultiplyButton()         {             this.Click += (s, e) => ClickAction(this);         }     } }

11.上面的是静态加载,那么现在我们使用MEF实现动态扩展运算器。桌面程序的动态扩展是动态加载DLL,而对于Silverlight的Web程序则是动态加载Xap包了。 新建普通Silverlight Application(Named DynamicExtension).

去掉勾选Add a test page that references the application. 1). 删掉App和Main等不必要的文件,只留一个空的Silverlight项目,以减少Xap包的大小。 2). 添加ContractLibrary和MEF框架集的引用(可以将引用程序集属性CopyLocal设置为false,因为我们在主工程中已经添加了,可以重用) 3). 添加类Division.cs.

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel.Composition; using ContractLibrary;

namespace DynamicExtension {     /// <summary>     /// 乘法运算器     /// </summary>     [Export(typeof(IOperate))]     public class DivisionButton : Button, IOperate     {         [Import("DivisionButtonContract", AllowRecomposition = true)]         public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }

[Import("DivisionSybomContract", AllowRecomposition = true)]         public string Symbol { set; get; }

[Import("ClickHandler")]         public OperateHandler ClickAction { get; set; }

#region IOperate 成员

public double Op(double left, double right)         {             return left * right;         }

#endregion

public DivisionButton()         {             this.Click += (s, e) => ClickAction(this);         }     } }

4).  添加配置类ComponentConfiguration.cs

代码

using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.ComponentModel.Composition;

namespace DynamicExtension {     /// <summary>     /// 为每个运算器的属性配置值     /// </summary>     public class ComponentConfiguration     {         [Export("DivisionButtonContract")]         public string AddLabel { get { return "Div"; } }         [Export("DivisionSybomContract")]         public string AddSymbol { get { return "/"; } }     } }

5). 修改Home.cs ,为其注册下载包的相关事件和回调

1. 代码

using System; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using System.Collections.ObjectModel; using System.ComponentModel.Composition.Hosting; using System.Reflection; using System.ComponentModel.Composition; using ContractLibrary;

namespace MefDemo {     public partial class Home : Page     {         [ImportMany(typeof(IOperate),AllowRecomposition = true)]         public ObservableCollection<IOperate> Operates = new ObservableCollection<IOperate>();

[Export("ClickHandler")]         public OperateHandler ClickHandler { get { return OperateButton_Click; } }

private PackageCatalog Catalog;

/// <summary>         /// 用于界面控件响应运算后的一些更新工作         /// </summary>         /// <param name="Operate">运算器</param>         public void OperateButton_Click(IOperate Operate)         {             try             {                 Symbol.Text = Operate.Symbol;                 double left = double.Parse(LeftNum.Text);                 double right = double.Parse(RightNum.Text);                 this.Result.Text = Operate.Op(left, right).ToString();             }             catch (Exception e)             {                 ChildWindow errorWin = new ErrorWindow(e);                 errorWin.Show();             }         }

public Home()         {             InitializeComponent();

this.Loaded += new RoutedEventHandler(Home_Loaded);             //注册按钮事件             this.DynamicLoadButton.Click += (s, e) =>             {                 //下载包                 Package.DownloadPackageAsync(                     new Uri("DynamicExtension.xap", UriKind.Relative),                     (args, package) => Catalog.AddPackage(package)                 );                 //包被添加到PackageCatalog后会自动重新组合                 //并对添加了AllowRecomposition = true属性的Import导入器重新输入数据             };         }

void Home_Loaded(object sender, RoutedEventArgs e)         {             //组合当前XAP包中所有部件(Parts)             Catalog = new PackageCatalog();             Catalog.AddPackage(Package.Current);             CompositionContainer container = new CompositionContainer(Catalog);             container.ComposeParts(this);

//组合后所有实现运算接口(IOperate)的运算器都将被自动填充到 Operates 集合。             //将运算器绑定到 ListBox 控件,用于呈现。             this.operateList.DataContext = Operates;         }

// Executes when the user navigates to this page.         protected override void OnNavigatedTo(NavigationEventArgs e)         {         }

} }

Ok,最终界面。 点击DynamicLoadOperate按钮后

    程序中还有很多细节没有展开说明,理论性的介绍可以参考MSDN和CodePlex上的文档。

Silverlight-MEF-DEMO的更多相关文章

  1. [SL] Silverlight + WCF Demo项目

    I:项目描述:利用 Silverlight+WCF 技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来: ...

  2. WPF第三方控件Telerik

    帮助文档:http://www.telerik.com/help/wpf/gridview-selection-via-checkbox.html Telerik专注于微软.Net平台的表示层与内容管 ...

  3. 流程设计器jQuery + svg/vml(Demo7 - 设计器与引擎及表单一起应用例子)

    去年就完成了流程设计器及流程引擎的开发,本想着把流程设计器好好整理一下,形成一个一步一步的开发案例,结果才整理了一点点,发现写文章比写代码还累,加上有事情要忙,结果就.. 明天要去外包驻场了,现把流程 ...

  4. 流程设计器jQuery + svg/vml(Demo6 - 增加结点属性及切换)

    到目前流程设计器流程结点的拖拽操作已基本完成,接下来就到结点的属性开发了.前面已经开发过流程模板的属性了,结点属性跟模板属性类似,从属性模板定义copy一份,然后按各结点类型进行调整就ok. 1.先来 ...

  5. 流程设计器jQuery + svg/vml(Demo5 - 撤消与重做)

    上篇完成了画线,接下来是撤消与重做. 代码:GoFlow_05.zip 演示地址:Demo 微信演示公众号: 另:Silverlight版 Silverlight版Demo

  6. 流程设计器jQuery + svg/vml(Demo4 - 画连线)

    流程结点可以添加了之后,接下来到画结点与结点之间的连线,效果图如下 很眼馋visio的连线可以折来折去,这里实现的连线比较简单. 首先是把连线的类型分为Z(折线).N(折线)及I(直线)3种类型,然后 ...

  7. 流程设计器jQuery + svg/vml(Demo3 - 添加流程结点)

    经过前面的准备工作,终于把设计器的主要UI界面搭建好了,接下来到添加流程结点,效果如下图 代码:GoFlow_03.zip 演示地址:Demo 微信演示公众号: 另:Silverlight版 Silv ...

  8. 流程设计器jQuery + svg/vml(Demo2 - UI界面增加属性显示)

    设计器UI界面有了,接下来结点的属性怎么显示呢,采用弹窗的话觉得不方便用户:用easyui的propertygrid在最右边显示,又觉得要引入easyui,使得插件变复杂了:最后决定自己写. 1.实现 ...

  9. 流程设计器jQuery + svg/vml(Demo1 - 构建设计器UI界面)

    之前用Silverlight实现过一个流程设计器(Demo),使用起来不是很方便.打算参考GooFlow,结合自己对工作流的理解,用jQuery改造实现一个,力求简单实用. 第一步是要构建设计器的UI ...

  10. Prism 4 文档 ---第3章 管理组件间的依赖关系

     基于Prism类库的应用程序可能是由多个松耦合的类型和服务组成的复杂应用程序,他们需要根据用户的动作发出内容和接收通知进行互动,由于他们是松耦合的,他们需要一种方式来互动和交流来传递业务功能的需求. ...

随机推荐

  1. 如何在 CentOS 7 中安装或升级最新的内核

    虽然有些人使用 Linux 来表示整个操作系统,但要注意的是,严格地来说,Linux 只是个内核.另一方面,发行版是一个完整功能的系统,它建立在内核之上,具有各种各样的应用程序工具和库. 在正常操作期 ...

  2. [转]NLP Tasks

    Natural Language Processing Tasks and Selected References I've been working on several natural langu ...

  3. linux线程学习

    按照书上写的,不知道为什么有问题: //已解决,参考最新的blog,哈哈 #include <stdlib.h> #include <pthread.h> #include & ...

  4. JAVA删除文件及文件夹

    JAVA在删除文件或文件夹时,在java.io.File类下有个delete的方法,并且可以返回true or false, 用这个方法来删除单个文件时,很好使,但在删除文件夹时,如果文件夹下面有文件 ...

  5. HDU 3018 Ant Trip (欧拉回路)

    Ant Trip Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  6. 在触屏设备上面利用html5裁剪图片(转)

    前言 现在触屏设备越来越流行,而且大多数已经支持html5了.针对此,对触屏设备开发图片裁剪功能, 让其可以直接处理图片,减轻服务端压力. 技术点 浏览器必须支持html5,包括fileReader, ...

  7. OAuth2.0实战之微信授权篇

    微信开发三大坑: 微信OAuth2.0授权 微信jssdk签名 微信支付签名 本篇先搞定微信OAuth2.0授权吧! 以简书的登陆页面为例,来了解一下oauth2.0验证授权的一些背景知识: 1) 传 ...

  8. Linux安装最新版Mono,Jexus(截至2015年12月30日)

    安装系统必备: yum -y install gcc gcc-c++ bison pkgconfig glib2-devel gettext make libpng-devel libjpeg-dev ...

  9. 跟我学SharePoint 2013视频培训课程—— 版本控制以及内容审批(14)

    课程简介 第14天,怎样在SharePoint 2013中启用版本控制以及内容审批 视频 SharePoint 2013 交流群 41032413

  10. 关于QueryCache的一次打脸

    [背景问题] 前一段时间给一套MySQL数据库加上了监控,运行一段时间后有人反馈监控到的insert,update,delete,select的数量中select的数量有像比 本应该的量少了不少! 我 ...