zoukankan      html  css  js  c++  java
  • 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_2inSL目录下 System.ComponentModel.Composition.dll) 在项目下添加两个类文件Package.cs和PackageCatalog.cs,这两个文件在最新的MEF版本中没有提供,主要用于加载silverlight的Xap包。 这两个文件在MEF框架的Sample中提供了(MEF_Beta_2SamplesPictureViewerPictureViewer.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上的文档。

  • 相关阅读:
    [js高手之路] es6系列教程
    [js高手之路] es6系列教程
    [js高手之路] es6系列教程
    [js高手之路]Node.js+jade+mongoose实战todolist(分页,ajax编辑,删除)
    [js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist
    [js高手之路]Node.js+jade+mongodb+mongoose实现爬虫分离入库与生成静态文件
    [js高手之路]Node.js+jade抓取博客所有文章生成静态html文件
    [js高手之路]Node.js模板引擎教程-jade速学与实战4-模板引用,继承,插件使用
    [js高手之路]Node.js模板引擎教程-jade速学与实战3-mixin
    [js高手之路]Node.js模板引擎教程-jade速学与实战2-流程控制,转义与非转义
  • 原文地址:https://www.cnblogs.com/lzjsky/p/3434696.html
Copyright © 2011-2022 走看看