使用MEF构建可扩展的Silverlight应用
“托管擴展性框架(Managed Extensibility Framework,簡稱MEF),是微軟 .NET框架下為提高應用和組件復用程度而推出的,用于使組件能夠最大化的重用 。使用MEF能夠使靜態編譯的.NET應用程序轉換為動態組合,這將是創建可擴展應 用、可擴展框架和應用擴展的好途徑。它將做為.NET Framework 4.0的組成部分 之一發布?,F在,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
轉載于:https://www.cnblogs.com/Areas/archive/2011/09/07/2169747.html
總結
以上是生活随笔為你收集整理的使用MEF构建可扩展的Silverlight应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WCF常见问题及解决方案
- 下一篇: Hadoop作业提交分析(三)