かずきのBlog

C#やJavaやRubyとメモ書き

目次

Blog 利用状況

ニュース

わんくまBlogが不安定になったため、前に書いてたはてなダイアリーにメインを移動します。
かずきのBlog@Hatena
技術的なネタは、こちらにも、はてなへのリンクという形で掲載しますが、雑多ネタははてなダイアリーだけに掲載することが多いと思います。
コメント
プログラマ的自己紹介
お気に入りのツール/IDE
プロフィール
経歴
広告
アクセサリ

書庫

日記カテゴリ

[C#][MEF]Managed Extensibility Framework入門 その8

過去の関連記事
[C#][MEF]Managed Extensibility Framework入門 その1
[C#][MEF]Managed Extensibility Framework入門 その2
[C#][MEF]Managed Extensibility Framework入門 その3
[C#][MEF]Managed Extensibility Framework入門 その4
[C#][MEF]Managed Extensibility Framework入門 その5
[C#][MEF]Managed Extensibility Framework入門 その6
[C#][MEF]Managed Extensibility Framework入門 その7

前回に引き続き、Catalog関連の部分をやってみようと思います。
今回のターゲットはDirectoryCatalogです。

こいつは、Directory内にあるアセンブリを自動で読み取って登録してくれるものです。
ということで、いつもどおりのコンソールアプリケーションにも飽きてきたので、WPFアプリケーションで実験してみようと思います。

WpfMEFという名前でWPFアプリケーションを作成します。
そして、Window1にExport属性をつけてコンテナにExportします。

[Export]
public partial class Window1 : Window
{
	// 省略
}

そして、App.xamlのStartupUri属性を消してStartupイベントを作り、そこに以下のようなコンテナの初期化コードと、Window1を表示する処理を書きます。

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Windows;

namespace WpfMEF
{
    public partial class App : Application
    {
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            // カレントディレクトリにあるアセンブリを対象にするDirectoryCatalogを作成
            var dirCatalog = new DirectoryCatalog(".");
            // 自アセンブリと↑をまとめたカタログを作成
            var catalog = new AggregateCatalog(
                new AssemblyCatalog(typeof(App).Assembly),
                dirCatalog);

            // コンテナを作成してDirectoryCatalogを明示的にコンテナに追加
            var con = new CompositionContainer(catalog);
            var batch = new CompositionBatch();
            batch.AddExportedObject<DirectoryCatalog>(dirCatalog);
            con.Compose(batch);

            // Window1を表示
            var window = con.GetExportedObject<Window1>();
            window.Show();
        }
    }
}

今回のキモは、DirectoryCatalogをあえてコンテナに登録しているところです。
こうすることで、DirectoryCatalogをImportできるようになります。

次に、Window1.xamlを編集していきます。Window1.xamlは、プラグインをホストするためのItemsControlと、プラグインの再読み込みを行うRefreshボタンがあるだけのシンプル構造にしました。

<Window x:Class="WpfMEF.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Loaded="Window_Loaded"
    Title="Window1">
    <DockPanel>
        <Button DockPanel.Dock="Top" Content="Refresh" Click="Button_Click" />
        <ItemsControl ItemsSource="{Binding Plugins}"/>
    </DockPanel>
</Window>

Window1のイベントとしては、Loadedイベントと、Refreshボタンのクリックイベントを登録しています。Loadedイベントとクリックイベントでは、プラグインの再読み込みを行っています。

コードとしては、こんな感じです。

using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Windows;

namespace WpfMEF
{
    [Export]
    public partial class Window1 : Window
    {
        // プラグイン
        [Import(AllowRecomposition=true)]
        public ExportCollection<FrameworkElement> ExportedFrameworkElements { get; set; }

        // カタログ
        [Import]
        public DirectoryCatalog Catalog { get; set; }

        // ここにプラグインに定義されたFrameworkElementが入る.
        // XAML側のItemsControlとバインドされているので、ここに入れたFrameworkElementが画面に
        // 表示される。
        public ObservableCollection<FrameworkElement> Plugins { get; private set; }

        // プラグインの初期化・再読み込みを行う
        private void LoadPlugins()
        {
            // 初回のときはコレクションを作成する
            if (Plugins == null)
            {
                this.Plugins = new ObservableCollection<FrameworkElement>();
            }

            // 再読み込み開始
            Catalog.Refresh();
            Plugins.Clear();

            // 新たなプラグインをコレクションに追加
            foreach(var plugin in ExportedFrameworkElements)
            {
                Plugins.Add(plugin.GetExportedObject());
            }
        }

        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            LoadPlugins();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            LoadPlugins();

            // とりあえずコードビハインドがViewModel役
            DataContext = this;
        }
    }
}

これで、プラグインをホストする側は完成です。
実行すると、ボタンがあるだけの悲しい画面が起動するのが確認できます。

プラグインを作成

プラグインのプロジェクトを2つ作成します。WpfPlugin1とWpfPlugin2という名前でWPFのユーザコントロールライブラリを作成します。System.ComponentModel.Composition.dllへの参照を各々追加しておきます。
それぞれ、非常にシンプルなユーザコントロールを1つずつ定義しておきます。

Plugin1のほうのユーザコントロール

<UserControl x:Class="WpfPlugin1.Plugin1Control"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <TextBlock Text="Plugin1" />
    </Grid>
</UserControl>

Plugin2のほうのユーザコントロール

<UserControl x:Class="WpfPlugin2.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <TextBlock Text="Plugin2" />
    </Grid>
</UserControl>

各々のコードビハインドで、クラスにExport(typeof(FrameworkElement))属性をつけます。
こうすることで、プラグインをホストする側のExportCollection<FrameworkElement>にImportされるようになります。

Plugin1のほうのコードビハインド

using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;

namespace WpfPlugin1
{
    [Export(typeof(FrameworkElement))]
    public partial class Plugin1Control : UserControl
    {
        public Plugin1Control()
        {
            InitializeComponent();
        }
    }
}

Plugin2のほうのコードビハインド

using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;

namespace WpfPlugin2
{
    [Export(typeof(FrameworkElement))]
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

それでは、実行して動きを見ていきます。
WpfMEFを起動してボタン1つだけの画面が起動することを確認します。
image

アプリケーションをいったん終了して、WpfMEFのbin\Debugフォルダに、WpfPlugin1.dllをコピーして起動します。
すると、画面にPlugin1が表示されます。
image

続いて、起動したままの状態でWpfPlugin2.dllをWpfEMFのbin\DebugフォルダにコピーしてRefreshボタンを押すと…
image

Plugin2が追加されました!
ということで、DirectoryCatalogを使うと、プラグインみたいな機能が割りと簡単に作れるということでした。

投稿日時 : 2009年7月10日 1:38

Feedback

# HxLivnqaExse 2011/12/13 20:46 http://www.drinkershealth.net/naltrexone-revia/

Of course, I understand a little about this post but will try cope with it!!...

# cheap burberry bags 2012/10/28 13:34 http://www.burberryoutletonlineshopping.com/burber

I believe this website has some rattling wonderful info for everyone. "The penalty of success is to be bored by the attentions of people who formerly snubbed you." by Mary Wilson Little.
cheap burberry bags http://www.burberryoutletonlineshopping.com/burberry-tote-bags.html

# Burberry Tie 2012/10/28 13:34 http://www.burberryoutletonlineshopping.com/burber

Some really choice posts on this site, saved to my bookmarks .
Burberry Tie http://www.burberryoutletonlineshopping.com/burberry-ties.html

# womens shirts 2012/10/28 13:34 http://www.burberryoutletonlineshopping.com/burber

wonderful points altogether, you just received a logo new|a new} reader. What might you suggest in regards to your post that you just made some days in the past? Any certain?
womens shirts http://www.burberryoutletonlineshopping.com/burberry-womens-shirts.html

# Burberry Watches 2012/10/28 13:34 http://www.burberryoutletonlineshopping.com/burber

Some truly wonderful content on this website, appreciate it for contribution. "Better shun the bait, than struggle in the snare." by John Dryden.
Burberry Watches http://www.burberryoutletonlineshopping.com/burberry-watches.html

# mens shirts 2012/10/28 13:35 http://www.burberryoutletonlineshopping.com/burber

you're in reality a excellent webmaster. The site loading pace is amazing. It seems that you're doing any unique trick. Furthermore, The contents are masterwork. you've done a magnificent activity on this topic!
mens shirts http://www.burberryoutletonlineshopping.com/burberry-men-shirts.html

# If you are going for finest contents like myself, only pay a visit this web page every day for the reason that it presents feature contents, thanks 2019/04/18 1:47 If you are going for finest contents like myself,

If you are going for finest contents like myself, only pay a visit this web
page every day for the reason that it presents feature contents, thanks

# I really like what you guys are usually up too. This sort of clever work and coverage! Keep up the superb works guys I've incorporated you guys to our blogroll. 2019/07/19 13:20 I really like what you guys are usually up too. Th

I really like what you guys are usually up
too. This sort of clever work and coverage! Keep up the superb works
guys I've incorporated you guys to our blogroll.

# Hey there! I've been reading your web site for some time now and finally got the courage to go ahead and give you a shout out from Dallas Texas! Just wanted to tell you keep up the fantastic work! 2019/09/05 19:08 Hey there! I've been reading your web site for som

Hey there! I've been reading your web site for some time now
and finally got the courage to go ahead and give you
a shout out from Dallas Texas! Just wanted to tell you keep up the
fantastic work!

タイトル
名前
Url
コメント