何となく作ってみた。
まず、コンテナを保持しておくためのstaticなクラスを用意する。
using System.ComponentModel.Composition.Hosting; namespace WpfMVVMBase.Markup { public static class ContainerProvider { public static CompositionContainer Container { get; set; } } }
using System; using System.Linq; using System.Windows; using System.Windows.Markup; namespace WpfMVVMBase.Markup { public class MefExtension : MarkupExtension { public string Contract { get; set; } public Type ContractType { get; set; } public MefExtension() { ContractType = typeof(FrameworkElement); } public override object ProvideValue(IServiceProvider serviceProvider) { // コンテナが無い場合は何もできないよね if (ContainerProvider.Container == null) return null; var exports = ContainerProvider.Container.GetExports( ContractType, null, Contract); // みつからない場合は何も返せない if (exports.Count() == 0) return null; // 単一項目の場合は、それを返す if (exports.Count() == 1) return exports.ElementAt(0).Value; // 複数ある場合はIEnumerableで返す return exports.Select(lazy => lazy.Value); } } }
使うときのイメージはこんな感じ。
using System.ComponentModel.Composition; namespace WpfMVVMBase { // とりあえず何も無いけど登録しておく [InheritedExport] public interface IShellModel { } public class ShellModel : IShellModel { } }
そして、何処かで1回コンテナを作成して、ContainerProviderのContainerに入れておきます。
var catalog = new AggregateCatalog( new AssemblyCatalog(Assembly.GetExecutingAssembly())); var container = new CompositionContainer(catalog); ContainerProvider.Container = container;
あとは、XAMLからさくっと使えます。
<Window x:Class="WpfMVVMBase.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Shell" Height="300" Width="300" xmlns:mef="clr-namespace:WpfMVVMBase.Markup" xmlns:l="clr-namespace:WpfMVVMBase" Content="{mef:Mef ContractType=l:IShellModel}"> </Window>