Managed Extensibility Framework(MEF)を使用してモジュール式Silverlightアプリケーションを開発する

MEFライブラリは比較的最近登場しましたが、使いやすさと効率性から.Net開発者の間で急速に人気を博しました。 これにより、最小レベルの接続パーツ(アプリケーション)パーツでモジュール式アプリケーションを構築できます。 このライブラリには、Dependency Injectionコンテナだけでなく、大量のインフラストラクチャも含まれます。アセンブリ内の構成要素を検索するための多くのメカニズム、リモートXAPファイル、.Net属性を使用して構成要素をマークするメカニズムなど。



デスクトップバージョンとは異なるバージョンのMEF for Silverlightがあります。 この記事では、SilverlightアプリケーションにMEFを使用する機能について説明します。



デスクトップ版との違い

SiverlightのMEFは、いくつかの特定のクラスを追加します。
Compositioninitializer
Silverlightでは、MEF開発者はCompositionInitializer



クラス(System.ComponentModel.CompositionInitialization.dllライブラリ)を使用することをお勧めします。このクラスを使用すると、このオブジェクトと他の依存エンティティのすべてのインポートを初期化して特定のオブジェクトを作成できます。 この機能は、アプリケーションコンポーネントの分散化が特に顕著であるSilverlightアプリケーションにとって特に重要です。



このクラスのSatisfyImports()



メソッドを初めて呼び出すときは、将来のSatisfyImports()



すべての呼び出しで使用されるグローバルコンテナーを作成します。 SatisfyImports



は、現在のアセンブリとすべての依存アセンブリ(つまり、XAPファイル全体)にあるすべてのオブジェクトをSatisfyImports



します。 作成中にインスタンス化されたオブジェクトは、最後のオブジェクトが破棄されるまでコンテナに残ります。 プログラムの終わりまで。



このクラスを使用するいくつかの機能があります。
  1. SatisfyImports()



    メソッドを呼び出すクラスには、 [Export]



    属性をSatisfyImports()



    ことはできません。
  2. オブジェクトは一度だけインスタンス化され、コンテナに保存されます。
  3. デフォルトでは、現在のXAPファイルのみがコンポジションに公開されますが、これは簡単に修正できます。
例:
public partial class Shell : UserControl<br>{<br> public MainPage()<br> {<br> ComposeContainer()<br> }<br><br> private void ComposeContainer()<br> {<br> CompositionInitializer.SatisfyImports( this );<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



DeploymentCatalog
このクラスは、XAPファイルの動的なロード用に設計されています。これにより、開発をさらに分散し、メインXAPファイルのサイズを小さくし、アプリケーションのダウンロード速度を上げることができます。存在する場合。



このクラスは、再構成(既存および追加された部分の再構成)の概念の不可欠な部分であり、再構成を許可する部分がある場合は後者を実行します。



DeploymentCatalog



を使用する機能:
  1. ブラウザキャッシュは、アプリケーションがオフラインのときに使用されます
  2. CompositionHost



    クラスを使用する必要があります(以下を参照)
  3. 同じアセンブリが異なるXAPファイルに存在する場合、 DeploymentCatalog



    はそれらをすべてディレクトリに追加しようとします。再構成が許可されていない場合、例外が発生する可能性があります。 CopyLocal=False



    を設定して、アプリケーション全体のアセンブリを複製するか、VS2010 XapsMinifierの拡張機能を使用する必要があります。
  4. マニフェストファイルで指定されたアセンブリのみがXAPからディレクトリにダウンロードされます
  5. ブラウザ外モードでは、ダウンロード可能なアセンブリはファイルシステムにキャッシュされません
例:
private void CancelLoading()<br>{<br> catalog.CancelAsync();<br>}<br><br> private void LoadXapFile( string xapPath)<br>{<br> DeploymentCatalog catalog = new DeploymentCatalog(xapPath);<br> catalog.DownloadCompleted += new EventHandler<AsyncCompletedEventArgs>(DownloadCompleted);<br> catalog.DownloadProgressChanged += new EventHandler<DownloadProgressChangedEventArgs>(ProgressChanged);<br> catalog.DownloadAsync();<br> _aggregateCatalog.Catalogs.Add(catalog);<br>}<br><br> void DownloadCompleted( object sender, System.ComponentModel.AsyncCompletedEventArgs e)<br>{<br> if (e.Error != null )<br> throw e.Error;<br>}<br><br> void catalog_DownloadProgressChanged( object sender, DownloadProgressChangedEventArgs e)<br>{<br> int progress = e.ProgressPercentage;<br> long received = e.BytesReceived;<br> long total = e.TotalBytesToReceive;<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



Compositionhost
このクラスは、パーツのエクスポート/インポートに関する情報を含むディレクトリと、パーツの構成を含むコンテナ間のリンクです。 このクラスを使用すると、アプリケーションの初期構成をオーバーライドできます(現在のXAPファイルからのみパーツをロードします)。 ディレクトリのセットを指定して、その内容を監視し、変更(追加/削除)が発生した場合は、既存のパーツの再構成を呼び出すことができます。



例:
public partial class Shell : UserControl<br>{<br> public MainPage()<br> {<br> ComposeContainer()<br> }<br><br> private void ComposeContainer()<br> {<br> _aggregateCatalog = new AggregateCatalog( new DeploymentCatalog());<br> CompositionHost.Initialize(_aggregateCatalog);<br> CompositionInitializer.SatisfyImports( this );<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



ExportFactory <T>
場合によっては、構成要素の複数のインスタンスを作成する必要があります。 たとえば、アプリケーションでユーザーがドキュメント(構成要素)の複数のコピーを作成できる場合、これは従来の手段では実現できません。 ExportFactory <T>の機能を使用する必要があります。



例:
[Export]<br> public class DocumentViewModel {<br><br> [Import] <br> public ExportFactory<IDocument> DocumentFactory<br> {<br> get ;<br> set ;<br> }<br><br> protected List <IDocument> Documents<br> {<br> get ;<br> set ;<br> }<br><br> public void CreateDocument() <br> {<br> Documents.Add(DocumentFactory.CreateExport().Value);<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



ExportFactory <T>を使用してコンポジションの一部を作成することにより、開発者は作成されたインスタンスの存続期間について全責任を負います。 インスタンスでメモリを解放する必要がある場合は、標準のDispose()



パターンを使用できます。



例:
[Export]<br> public class DocumentViewModel : IDisposable <br>{<br> private bool isDisposed = false ;<br> [Import] <br> public ExportFactory<IDocument> DocumentFactory<br> {<br> get ;<br> set ;<br> }<br><br> private List <ExportLifetimeContext<IDocument>> ExportLifeTimeContextList<br> {<br> get ;<br> set ;<br> }<br><br> protected List <IDocument> Documents<br> {<br> get ;<br> set ;<br> }<br><br> public void CreateDocument() <br> {<br> ExportLifetimeContext<IDocument> LifeTimeContext = DocumentFactory.CreateExport();<br> ExportListLifeTimeContext.Add(LifeTimeContext);<br> Documents.Add(LifeTimeContext.Value);<br> }<br><br> public void Dispose()<br> {<br> Dispose( true );<br> GC.SuppressFinalize( this );<br> }<br><br> public void Dispose( bool disposing)<br> {<br> if (isDisposed)<br> return ;<br><br> if (disposing)<br> {<br> foreach (IDisposable d in ExportLifeTimeContextList)<br> d.Dispose();<br> }<br> <br> isDisposed = true ;<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



再構成メカニズムの実装例

SilverlightアプリケーションでMEFを使用するシンプルさとパワーを反映する例として、アプリケーションコントロールのテーマサポートの実装を選択しました。



アプリケーションは次の要件を満たしている必要があります。
  1. サポートトピック
  2. テーマを使用してサードパーティのXAPファイルをダウンロードする機能を持っている
  3. XAPファイルをダウンロードすると、利用可能なトピックのリストが更新されます(再構成)
  4. テーマの選択は、コントロールの外観の変更につながるはずです
へのサポート
テーマのサポートを実装するために、いくつかの既成トピックのセットを提供する公開プロジェクトに目を向けました。 これらのプロジェクトのうち、xamlファイルと基本的なコントロールのテーマを使用します。



各テーマは、個別のXAPファイルの個別のアセンブリにあります。 テーマ自体はリソースとして保存され、リクエストに応じて取得されます。



IThemeLoader



インターフェイスを実装するクラスは、トピックにアクセスするためのメカニズムとして使用されます。 このクラスは、必要なリソースを抽出でき、トピックの名前を含みます。



例:
[InheritedExport]<br> public interface IThemeLoader<br>{<br> string Name<br> {<br> get ;<br> }<br><br> IEnumerable <ResourceDictionary> Resources<br> {<br> get ;<br> }<br><br>}<br><br><br> public class ThemeLoader : ThemeLoaderBase<br>{<br><br> #region IThemeLoader Members<br><br> public override string Name<br> {<br> get <br> {<br> return "Accent" ;<br> }<br> }<br><br> public override IEnumerable <ResourceDictionary> Resources<br> {<br> get <br> {<br> yield return LoadResourceDictionary( "/SLandMEFdevcamp.AccentTheme;component/Style.xaml" );<br> }<br> }<br><br> #endregion <br> <br> /* <br> protected virtual ResourceDictionary LoadResourceDictionary(string uri) <br> { <br> return new ResourceDictionary <br> { <br> Source = new Uri(uri, UriKind.Relative) <br> }; <br> } <br> */ <br>}<br> <br> * This source code was highlighted with Source Code Highlighter .



InheritedExport



属性は、この属性でマークされたインターフェイスのすべての実装をエクスポートする必要があることを示します。



サードパーティのXAPファイルをダウンロードする
サードパーティのXAPファイルをサポートするには、アプリケーションのメインフォームにXAPファイルアドレスの入力フィールドとダウンロード開始ボタンを配置します。 ダウンロードは、再構成を開始するDeploymentCabinet



を使用して行われます。



再構成が行われるとすぐに、 IThemeLoader



実装のリストがIThemeLoader



、利用可能なトピックの新しいリストがUIに表示されます。



例:
private AggregateCatalog _aggregateCatalog = null ;<br> private IEnumerable <IThemeLoader> themesLoaders;<br><br> private void ComposeContainer()<br>{<br> _aggregateCatalog = new AggregateCatalog( new DeploymentCatalog());<br> CompositionHost.Initialize(_aggregateCatalog);<br> CompositionInitializer.SatisfyImports( this );<br>}<br><br>[ImportMany(AllowRecomposition = true )]<br> public IEnumerable <IThemeLoader> ThemesLoaders<br>{<br> get <br> {<br> return themesLoaders;<br> }<br> set <br> {<br> themesLoaders = value ;<br> RaisePropertyChanged( "ThemesLoaders" );<br> }<br>}<br><br> private IThemeLoader theme;<br> public IThemeLoader Theme<br>{<br> get <br> {<br> return theme;<br> }<br> set <br> {<br> theme = value ;<br> LoadTheme( value );<br> RaisePropertyChanged( "Theme" );<br> }<br>}<br><br> private void LoadTheme(IThemeLoader themeLoader)<br>{<br> if (themeLoader.Resources == null || !themeLoader.Resources.Any())<br> return ;<br><br> App.Current.Resources.MergedDictionaries.Clear();<br><br> foreach ( var resourceDict in themeLoader.Resources)<br> App.Current.Resources.MergedDictionaries.Add(resourceDict);<br>}<br><br> private void Button_Click( object sender, System.Windows.RoutedEventArgs e)<br>{<br> DeploymentCatalog catalog = new DeploymentCatalog(XapUrlTextBox.Text);<br> catalog.DownloadAsync();<br><br> _aggregateCatalog.Catalogs.Add(catalog);<br>} <br><br> * This source code was highlighted with Source Code Highlighter .



この場合、テーマを含むXAPファイルはメインXAPファイルと同じフォルダーにあるため、完全なURLなしでXAPファイルの名前のみを指定できます。 たとえば、SLandMEFdevcamp.AccentTheme.xap、SLandMEFdevcamp.Win7Theme.xapなどです。



このコードのロジックは次のとおりです。 プログラムの結果はここで見ることができます。



おわりに

MEFには、再構成、構成の一部を登録する厳密に定義された場所がないなど、多数の利点があります。



MEF for Silverlightには、デスクトップバージョンでも使用できない追加機能があり、さらに柔軟なプログラムを構築できます。



再構成機能を使用すると、プログラム操作中にコンポーネントのセットを直接変更できます。これは、機能、作業モジュールなどの動的な接続/切断が必要な場合に非常に重要です。



プロジェクトのソースコード

ソースコードはこちらからダウンロードできます



Upd: ExportFactory<T>



クラスが、 MEF 2 Preview 2のライブラリのデスクトップバージョンに追加ExportFactory<T>



れました。



All Articles