zoukankan      html  css  js  c++  java
  • 使用MEF构建可扩展的Silverlight应用

    “托管扩展性框架(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.Navi gation"
               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就像一个 个管道一样相互连接。

    # 按照这样的设计,我们想要对其进行扩展,就必须把接口分离。新建一个 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项目的 引用

    # 再新建一个Silverlight ClassLibrary Project (Named StaticExtension),,这个工程就是我们用来静态扩展的DLL。

    a).在工程下新建我们的运算器类,AddButton.cs , SubButton.cs.(代码不变 ).

    b).但注意要添加对ContractLibrary项目的引用和MEF的框架集引用) 。

    c).添加全局属性配置类(ComponentConfiguration.cs)

    d).删除主工程中的ComponetOperater.cs.

    e).添加对StaticExtension的引用.

     

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

    那么下面是添加一个新的乘法运算所要做的工作。

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

    # 上面的是静态加载,那么现在我们使用MEF实现动态扩展运算器。桌面程序 的动态扩展是动态加载DLL,而对于Silverlight的Web程序则是动态加载Xap包了 。

    新建普通Silverlight Application(Named DynamicExtension).

     

    11.去掉勾选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上 的文档。

    源码下载:http://download.csdn.net/source/2062158

    Powered By D&J (URL:http://www.cnblogs.com/Areas/)
  • 相关阅读:
    oracle查询当天数据三种方式性能对比
    APPCAN IDE中安装emmet插件
    MAS 移动业务整合系统
    SDK 移动应用开发系统
    移动应用开发平台介绍
    安装Sublime Text 3插件的方法
    2014勿勿已过,2015已迎面而来
    入驻博客园
    zkw线段树
    贪心题
  • 原文地址:https://www.cnblogs.com/Areas/p/2169747.html
Copyright © 2011-2022 走看看