Silverlight-MEF-DEMO
“托管扩展性框架(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的更多相关文章
- [SL] Silverlight + WCF Demo项目
I:项目描述:利用 Silverlight+WCF 技术,模拟资源管理器(如图1)功能,通过地址栏输入本地文件夹路径,然后将解析出来的该目录下所有文件(夹)存储到数据库中,然后再加载到界面上显示出来: ...
- WPF第三方控件Telerik
帮助文档:http://www.telerik.com/help/wpf/gridview-selection-via-checkbox.html Telerik专注于微软.Net平台的表示层与内容管 ...
- 流程设计器jQuery + svg/vml(Demo7 - 设计器与引擎及表单一起应用例子)
去年就完成了流程设计器及流程引擎的开发,本想着把流程设计器好好整理一下,形成一个一步一步的开发案例,结果才整理了一点点,发现写文章比写代码还累,加上有事情要忙,结果就.. 明天要去外包驻场了,现把流程 ...
- 流程设计器jQuery + svg/vml(Demo6 - 增加结点属性及切换)
到目前流程设计器流程结点的拖拽操作已基本完成,接下来就到结点的属性开发了.前面已经开发过流程模板的属性了,结点属性跟模板属性类似,从属性模板定义copy一份,然后按各结点类型进行调整就ok. 1.先来 ...
- 流程设计器jQuery + svg/vml(Demo5 - 撤消与重做)
上篇完成了画线,接下来是撤消与重做. 代码:GoFlow_05.zip 演示地址:Demo 微信演示公众号: 另:Silverlight版 Silverlight版Demo
- 流程设计器jQuery + svg/vml(Demo4 - 画连线)
流程结点可以添加了之后,接下来到画结点与结点之间的连线,效果图如下 很眼馋visio的连线可以折来折去,这里实现的连线比较简单. 首先是把连线的类型分为Z(折线).N(折线)及I(直线)3种类型,然后 ...
- 流程设计器jQuery + svg/vml(Demo3 - 添加流程结点)
经过前面的准备工作,终于把设计器的主要UI界面搭建好了,接下来到添加流程结点,效果如下图 代码:GoFlow_03.zip 演示地址:Demo 微信演示公众号: 另:Silverlight版 Silv ...
- 流程设计器jQuery + svg/vml(Demo2 - UI界面增加属性显示)
设计器UI界面有了,接下来结点的属性怎么显示呢,采用弹窗的话觉得不方便用户:用easyui的propertygrid在最右边显示,又觉得要引入easyui,使得插件变复杂了:最后决定自己写. 1.实现 ...
- 流程设计器jQuery + svg/vml(Demo1 - 构建设计器UI界面)
之前用Silverlight实现过一个流程设计器(Demo),使用起来不是很方便.打算参考GooFlow,结合自己对工作流的理解,用jQuery改造实现一个,力求简单实用. 第一步是要构建设计器的UI ...
- Prism 4 文档 ---第3章 管理组件间的依赖关系
基于Prism类库的应用程序可能是由多个松耦合的类型和服务组成的复杂应用程序,他们需要根据用户的动作发出内容和接收通知进行互动,由于他们是松耦合的,他们需要一种方式来互动和交流来传递业务功能的需求. ...
随机推荐
- 【php+uploadify3.2】上传按钮点击一点反应都没有,原因
原因: 代码没有问题,这个原因也困扰我一段时间,是由于浏览器禁用了flash,需要放开,操作方法如下: 在谷歌浏览器输入:chrome://settings/content/flash 然后添加需要该 ...
- <转>lua解释执行脚本流程
本文转自:http://www.cnblogs.com/zxh1210603696/p/4458473.html #include "lua.hpp" #include <i ...
- linux shell 脚本攻略学习3
1.Bash中的READ命令 #读取n个字符存入变量 read -n number_of_chars variable_name 示例: amosli@amosli-pc:~$ read -n var ...
- APP缓存数据线程安全问题
问题 一般一个 iOS APP 做的事就是:请求数据->保存数据->展示数据,一般用 Sqlite 作为持久存储层,保存从网络拉取的数据,下次读取可以直接从 Sqlite DB 读取.我们 ...
- Linux主要shell命令详解(上)
[摘自网络] kill -9 -1即实现用kill命令退出系统 Linux主要shell命令详解 [上篇] shell是用户和Linux操作系统之间的接口.Linux中有多种shell,其中缺省使用的 ...
- 记录:js删除数组中某一项或几项的几种方法(转)
1:js中的splice方法 splice(index,len,[item]) 注释:该方法会改变原始数组. splice有3个参数,它也可以用来替换/删除/添加数组内某一个或者几个值 inde ...
- 【转】IT业给世界带来的危机
IT业给世界带来的危机 昨天写了文章之后,回忆起这几年在湾区的经历,觉得自己是一个很不幸的人.然而就在今天,我的自怜奇妙的转换成了另一种感情,因为我看到了更不幸的人…… 正在女朋友 Cinny 的父母 ...
- ldd 的一个安全问题
我们知道“ldd”这个命令主要是被程序员或是管理员用来查看可执行文件所依赖的动态链接库的.是的,这就是这个命令的用处.可是,这个命令比你想像的要危险得多,也许很多黑客通过ldd的安全问题来攻击你的服务 ...
- 《从零開始学Swift》学习笔记(Day 65)——Cocoa Touch设计模式及应用之选择器
原创文章,欢迎转载.转载请注明:关东升的博客 实现目标与动作关联使用UIControl类addTarget(_:action:forControlEvents:)方法,演示样例代码例如以下: butt ...
- SharePoint CAML In Action——Part II
在SharePoint中,相对于Linq to SharePoint而言,CAML是轻量化的.当然缺点也是显而易见的,"Hard Code"有时会让你抓狂.在实际场景中,经常会根据 ...