かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Silverlight4でMEFベースのアプリを作るための小さな起動用クラス

Silverlight 4でMEFベースのアプリケーションを作りたいと思ったら、以下のようなクラスを準備するとよさそうです。

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.Hosting;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Primitives;

namespace BootSample
{
    public class Bootstrapper<T>
    {
        [Import]
        public T Shell { get; set; }

        // デフォルトのコンテナを使う
        public Bootstrapper()
        {
        }

        // カタログでコンテナを初期化
        public Bootstrapper(params ComposablePartCatalog[] catalogs)
        {
            CompositionHost.Initialize(catalogs);
        }

        // コンテナを初期化
        public Bootstrapper(CompositionContainer container)
        {
            CompositionHost.Initialize(container);
        }

        public void Run(Application app)
        {
            // Shellを取得して
            CompositionInitializer.SatisfyImports(this);
            // RootVisualに設定する
            app.RootVisual = Shell as UIElement;
        }
    }
}

非常にシンプルなクラスでApplicationのStartupイベント内で使用します。使い方は簡単です。メインにしたいウィンドウにExport属性をつけます。ここでは新規作成したときに作られるMainPageにつけました。

[Export]
public partial class MainPage : UserControl
{
  // 省略
}

Startupイベントの中も非常にシンプルです。

private void Application_Startup(object sender, StartupEventArgs e)
{
    new Bootstrapper<MainPage>().Run(this);
}

MainPage自体がMEFのコンテナから取得されるようになるので、後は、そこを皮切りにしてImportで繋いでやればOKです。カタログで色々初期化したいときは、Bootstrapperを作ってる部分を

new Bootstrapper<MainPage>(
    new AssemblyCatalog(typeof(App).Assembly),
    CreateDeploymentCatalog("SilverlightApplication1.xap"),
    new TypeCatalog(typeof(Hoge)));

private DeploymentCatalog CreateDeploymentCatalog(string path)
{
    var result = new DeploymentCatalog(path);
    result.DonloadAsync();
    return result;
}

みたいにすれば、お好みで色々なクラスをMEFで管理してもらえます。