読者です 読者をやめる 読者になる 読者になる

プログラマーな日々

プログラマーをやっています。好きなツール:WorkFlowy、好きな言語:C#、好きなサービス:Backlog、好きなAWS:AWS Lambda。

MEFでWPFのプラグインを実装する(複数プラグインをファイル名で指定して読み込む)改良版

.NET MEF DI WPF

前回(以下のエントリー)の実装を改良します。AggregateCatalogクラスでカタログを集約し、一度に読み込めるようにします。
MEFでWPFのプラグインを実装する(複数プラグインをファイル名で指定して読み込む) - プログラマーな日々


アプリ実行

プラグインのメソッドが呼ばれ、ウィンドウが表示されます。

プロジェクト構成

  • Pluginプロジェクト

クラスライブラリプロジェクトです。プラグインのインターフェースを定義します。前回と同じです。

  • HogePluginプロジェクト

WPFユーザーコントロールライブラリプロジェクトです。プラグインの実装クラスを含みます。ビルドしてアセンブリを所定のディレクトリ(D:\@Sandbox\Plugin)に配置します。前回と同じです。

  • FugaPluginプロジェクト

WPFユーザーコントロールライブラリプロジェクトです。プラグインの実装クラスを含みます。ビルドしてアセンブリを所定のディレクトリ(D:\@Sandbox\Plugin)に配置します。前回と同じです。

  • Mainプロジェクト

WPFアプリケーションプロジェクトです。プラグインを読み込みます。Pluginプロジェクトを参照しますが、HogePluginプロジェクト、FugaPluginプロジェクトは参照しません。AggregateCatalogクラスを使用するように変更します。

Pluginプロジェクト

IPlugin.cs
namespace Plugin {
    public interface IPlugin {
        void Execute();
    }
}

HogePluginプロジェクト

HogeWindow.xaml
<Window x:Class="HogePlugin.HogeWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="HogeWindow" Height="100" Width="300">
</Window>
HogeWindow.xaml.cs
using System.ComponentModel.Composition;
using System.Windows;
using Plugin;

namespace HogePlugin {
    /// <summary>
    /// 型を指定してExport属性を指定します。
    /// </summary>
    [Export(typeof(IPlugin))]
    public partial class HogeWindow : Window, IPlugin {
        public HogeWindow() {
            InitializeComponent();
        }

        void IPlugin.Execute() {
            this.Title = "Hello World, Hoge";
            this.Show();        
        }
    }
}

FugaPluginプロジェクト

FugaWindow.xaml
<Window x:Class="FugaPlugin.FugaWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="FugaWindow" Height="100" Width="300">
</Window>
FugaWindow.xaml.cs
using System.ComponentModel.Composition;
using System.Windows;
using Plugin;

namespace FugaPlugin {
    /// <summary>
    /// 型を指定してExport属性を指定します。
    /// </summary>
    [Export(typeof(IPlugin))]
    public partial class FugaWindow : Window, IPlugin {
        public FugaWindow() {
            InitializeComponent();
        }

        void IPlugin.Execute() {
            this.Title = "Hello World, Fuga";
            this.Show();        
        }
    }
}

Mainプロジェクト

App.xaml
<Application x:Class="Main.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
App.xaml.cs
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Windows;
using Plugin;

namespace Main {
    public partial class App : Application {
        /// <summary>
        /// このプロパティにプラグインを読み込みます。privateなプロパティでもOKです。
        /// </summary>
        [ImportMany]
        private List<IPlugin> Plugins { get; set; }

        public App() {
            this.Plugins = new List<IPlugin>();
            this.LoadPlugins();
            this.Plugins.ForEach(p => p.Execute());
        }

        /// <summary>
        /// 所定のディレクトリにあるプラグインdllをファイル名を指定して読み込みます。
        /// </summary>
        private void LoadPlugins() {
            DirectoryCatalog[] catalogs = this.GetDirectoryCatalogs("HogePlugin.dll", "FugaPlugin.dll");
            using (AggregateCatalog aggregateCatalog = new AggregateCatalog(catalogs))
            using (CompositionContainer container = new CompositionContainer(aggregateCatalog)) {
                container.SatisfyImportsOnce(this);
            }
        }

        private DirectoryCatalog[] GetDirectoryCatalogs(params string[] fileNames) {
            DirectoryCatalog[] catalogs = new DirectoryCatalog[fileNames.Length];

            for (int i = 0; i < fileNames.Length; i++) {
                catalogs[i] = new DirectoryCatalog(@"D:\@Sandbox\Plugin", fileNames[i]);
            }
            
            return catalogs;
        }
    }
}

参考

AggregateCatalog クラス (System.ComponentModel.Composition.Hosting)
ComposablePartCatalog オブジェクトの要素を結合するカタログ。