MEF:在我的用户控件中创建一个 ViewModel

MEF: Creating a ViewModel in my UserControls

我目前正在将我的 WPF/MVVM 应用程序从 Ninject 转换为 MEF 以利用一些插件架构。没有 Prism 或 Unity,我也不想走那条路。我正在使用 VS2015 和 .Net 4.6。

我使用了在 MVVM Light 中流行的技术,在该技术中,您使用 Ninject 在 XAML 中实例化 ViewModel。

  public static ImageViewModel ImageVM => Kernel.Get<ImageViewModel>();

但现在我要转到 MEF,我想看看是否有其他选择。目前在 Stack Exchange 上回答的大多数帖子都相当陈旧,我希望现在 .NET 4.5 可用时有一些新的替代方案可用。


tl;dr

我有一个包含 10 个用户控件的 Window。每个用户控件都附加了一个新的 ViewModel 实例。由于 window 正在 xaml 中创建用户控件,我如何才能将我的 ViewModel 的唯一实例放入每个控件中?

public partial class FingerprintControl{

    public FingerprintControl() {
        InitializeComponent();
    }

    [Import]
    public FingerprintControlViewModel ViewModel
    {
        get { return DataContext as FingerprintControlViewModel; }
        set { DataContext = value; }
    }

我看到的一个建议说要添加

    CompositionInitializer.SatisfyImports(this);

在 InitializeComponent() 之后。但那只是 Silverlight class.

我查看了 https://www.nuget.org/packages/Microsoft.Composition/,但网站上完全没有 MEF 2 的文档。

我还看到 ExportFactory 已添加到 MEF 2,但不确定这是否有帮助。

我确实在 MEF 2 中找到了静态方法 CompositionContextExtensions.SatisfyImports,但我不知道如何处理它。文档只说,"Satisfies the imports of the specified object from the specified context."(不是真正有用的...)

我们对 Mef 使用 class 包装器,并为我们所有的应用程序使用静态方法:

public class Mef
{
    private static CompositionContainer container = null;
    public static CompositionContainer Container { get { return container; } }

    private static AggregateCatalog catalog;

    public static void Initialize()
    {
        catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new DirectoryCatalog(path: ".", searchPattern: "*.exe"));
        catalog.Catalogs.Add(new DirectoryCatalog(path: ".", searchPattern: "*.dll"));
        container = new CompositionContainer(catalog);
        StartWatch();
    }

    private static void StartWatch()
    {
        var watcher = new FileSystemWatcher() { Path = ".", NotifyFilter = NotifyFilters.LastWrite };
        watcher.Changed += (s, e) =>
        {
            string lName = e.Name.ToLower();
            if (lName.EndsWith(".dll") || lName.EndsWith(".exe"))
                Refresh();
        };
        watcher.EnableRaisingEvents = true;
    }

    public static void Refresh()
    {
        foreach (DirectoryCatalog dCatalog in catalog.Catalogs)
            dCatalog.Refresh();
    }
}

(注意:我们使用上面的方法根据用户的需要将插件按需动态加载到我们的应用程序中。您可能想使用不同的目录系统 - 有几个可供选择)

然后我们在应用程序生命周期的早期初始化 class,通常在 App.Xaml 代码隐藏构造函数中:

    public App()
    {
        this.InitializeComponent();
        Mef.Initialize();
    }

当我有一个基本级别的 mef-import 时,在 class/code-behind 构造函数调用中:

Mef.Container.SatisfyImports(this);

希望对您有所帮助。