带有MEF2的WPF MvvM中的插件

带有MEF2的WPF MvvM中的插件,wpf,mvvm,mef,mef2,Wpf,Mvvm,Mef,Mef2,我已经尝试了以下非常好的教程来迁移到MEF2,但是由于某些原因,这些部件没有显示在目录中。从MEF2开始,我想使用API配置(RegistrationBuilder类)(这里是一个示例:),也许有人知道如何将MEF2正确地应用到教程中。多谢各位 下面是解决方案的概述: 在MainViewModel.cs中,我还不知道如何将导入集成到RegistrationBuilder中。您可以检查其余的代码吗?谢谢 namespace WPF_MEF_App { public class MainW

我已经尝试了以下非常好的教程来迁移到MEF2,但是由于某些原因,这些部件没有显示在目录中。从MEF2开始,我想使用API配置(RegistrationBuilder类)(这里是一个示例:),也许有人知道如何将MEF2正确地应用到教程中。多谢各位

下面是解决方案的概述:

在MainViewModel.cs中,我还不知道如何将导入集成到
RegistrationBuilder
中。您可以检查其余的代码吗?谢谢

namespace WPF_MEF_App
{
    public class MainWindowModel : NotifyModelBase
    {
        public ICommand ImportPluginCommand { get; protected set; }
        private IView PluginViewVar;

       [Import(typeof(IView), AllowRecomposition = true, AllowDefault = true)]
        public IView PluginView
        {
            get { return PluginViewVar; }
            set{ PluginViewVar = value; NotifyChangedThis();}
        }

        [ImportMany(typeof(IView), AllowRecomposition = true)]
        public IEnumerable<Lazy<IView>> Plugins;

        private AggregateCatalog catalog;
        private CompositionContainer container;

        public MainWindowModel()
        {
            ImportPluginCommand = new DelegateCommand(ImportPluginExecute);
            RegistrationBuilder builder = new RegistrationBuilder();
            builder.ForType<PluginSecondScreen>()
                .Export<IView>(eb =>
                {
                    eb.AddMetadata("Name", "PluginSecond");
                })
                .SetCreationPolicy(CreationPolicy.Any);
            //.ImportProperties(pi => pi.Name == "IView",
            //        (pi, ib) => ib.AllowRecomposition());

            builder.ForType<CalculatorScreen>()
                .Export<IView>(eb =>
                {
                    eb.AddMetadata("Name", "CalculatorScreen");
                })
                .SetCreationPolicy(CreationPolicy.Any);
                //.ImportProperties(pi => pi.Name == "IView",
                //        (pi, ib) => ib.AllowRecomposition());

            catalog = new AggregateCatalog();

            string pluginsPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            catalog.Catalogs.Add(new DirectoryCatalog(pluginsPath, "Plugin*.dll"));
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder));

            //also we add to a search path a subdirectory plugins
            pluginsPath = Path.Combine(pluginsPath, "plugins");
            if (!Directory.Exists(pluginsPath))
                Directory.CreateDirectory(pluginsPath);
            catalog.Catalogs.Add(new DirectoryCatalog(pluginsPath, "Plugin*.dll"));            

            //Create the CompositionContainer with the parts in the catalog.
            container = new CompositionContainer(catalog);
        }

        private void ImportPluginExecute()
        {
            //refresh catalog for any changes in plugins
            //catalog.Refresh();

            //Fill the imports of this object
            //finds imports and fills in all preperties decorated
            //with Import attribute in this instance
            container.ComposeParts(this);
            //another option
            //container.SatisfyImportsOnce(this);
        }
    }
}
名称空间WPF\u MEF\u应用程序
{
公共类MainWindowModel:NotifyModelBase
{
公共ICommand importPlugin命令{get;protected set;}
私有IView-PluginViewVar;
[导入(typeof(IView),AllowRecomposition=true,AllowDefault=true)]
公共IView插件查看
{
获取{return PluginViewVar;}
设置{PluginViewVar=value;NotifyChangedThis();}
}
[ImportMany(typeof(IView),AllowRecomposition=true)]
公共IEnumerable插件;
私有聚合目录;
专用合成容器;
公共主窗口模型()
{
ImportPluginCommand=新的DelegateCommand(ImportPluginExecute);
RegistrationBuilder=新的RegistrationBuilder();
builder.ForType()
.出口(eb=>
{
eb.添加元数据(“名称”、“插件绑定”);
})
.SetCreationPolicy(CreationPolicy.Any);
//.ImportProperties(pi=>pi.Name==“IView”,
//(pi,ib)=>ib.allowercomposition());
builder.ForType()
.出口(eb=>
{
eb.添加元数据(“名称”、“计算器屏幕”);
})
.SetCreationPolicy(CreationPolicy.Any);
//.ImportProperties(pi=>pi.Name==“IView”,
//(pi,ib)=>ib.allowercomposition());
catalog=新的AggregateCatalog();
字符串pluginsPath=Path.GetDirectoryName(Assembly.getExecutionGassembly().Location);
catalog.Catalogs.Add(新目录目录(pluginsPath,“Plugin*.dll”);
catalog.Catalogs.Add(新的AssemblyCatalog(Assembly.getExecutionGassembly(),builder));
//我们还向搜索路径添加了一个子目录插件
pluginsPath=Path.Combine(pluginsPath,“plugins”);
如果(!Directory.Exists(pluginsPath))
CreateDirectory(pluginsPath);
catalog.Catalogs.Add(新目录目录(pluginsPath,“Plugin*.dll”);
//使用目录中的零件创建CompositionContainer。
容器=新的合成容器(目录);
}
私有void ImportPluginExecute()
{
//刷新目录以查看插件中的任何更改
//catalog.Refresh();
//填充此对象的导入
//查找导入内容并填充所有preperties
//在此实例中使用Import属性
容器。组件(本);
//另一种选择
//集装箱。满足进口(本);
}
}
}
以下是两个插件: 我已经在这里对导出进行了注释,因为
RegistrationBuilder
不再需要它们。
我检查了你的尝试。需要改进的几点

  • 通常,您应该在中心位置配置容器, 通常在启动时的应用程序入口点,例如在 App.xaml.cs的方法。类从不创建自己的容器来导入其依赖项。如果这是必要的,考虑导入(不通过容器)。< /LI>
  • 您必须通过构造函数(推荐)或属性而不是字段导入依赖项。因此,您需要将
    get
    set
    添加到
    PluginView
    Plugins
    的定义中
  • 您应该使用基于注释的依赖项解析或基于API的依赖项解析。别把它混在一起。因此,您必须从
    MainWindowModel
    中的所有属性中删除
    Import
    属性
  • 一个接口不能有多个实现,例如
    IView
    和一个导入(基数)。您应该导入一组具体类型,只注册一个具体类型,或者为每个具体类型引入一个专用接口(例如
    PluginSecondScreen
    ICalculatorScreen
    ),其中每个接口继承共享接口(例如
    IView
  • 完成初始化后,不要忘记处置
    合成容器
  • SetCreationPolicy(CreationPolicy.Any)
    CreationPolicy一样是多余的。Any
    是默认值,通常默认为
    CreationPolicy.Shared
  • 尝试在任何地方使用接口
  • 使用类或类成员或类型名称时,避免使用
    字符串
    文字。改用
    nameof

    导入属性(pi=>pi.Name==“插件”)
    应该是:
    ImportProperties(pi=>pi.Name==nameof(MainWindowModel.Plugins)
    。这使得重构更加容易
  • MainWindowModel.cs

    class MainWindowModel
    {
      // Import a unique matching type or import a collection of all matching types (see below).
      // Alternatively let the property return IView and initialize it form the constructor,
      // by selecting an instance from the `Plugins` property.
      public IPluginSecondScreen PluginView { get; set; }
    
      // Import many (implicit)
      public IEnumerable<Lazy<IView>> Plugins { get; set; }
    }
    
    接口实现:

    interface IView
    {
    }
    
    interface IPluginSecondScreen : IView
    {
    }
    
    interface ICalculatorScreen : IView
    {
    }
    
    class PluginSecondScreen : UserControl, IPluginSecondScreen
    {
    }
    
    class CalculatorScreen : UserControl, ICalculatorScreen
    {
    }
    
    private void Run(object sender, StartupEventArgs e)
    {
      RegistrationBuilder builder = new RegistrationBuilder();
      builder.ForTypesDerivedFrom<IView>()
        .ExportInterfaces();
    
      builder.ForType<MainWindowModel>()
        .Export()
        .ImportProperties(
          propertyInfo => propertyInfo.Name.Equals(nameof(MainWindowModel.Plugins), StringComparison.OrdinalIgnoreCase) 
            || propertyInfo.Name.Equals(nameof(MainWindowModel.PluginView), StringComparison.OrdinalIgnoreCase));
    
      var catalog = new AggregateCatalog();
      catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "InternalShared.dll", builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginCalculator.dll", builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginSecond.dll", builder));
    
      using (var container = new CompositionContainer(catalog))
      {    
        MainWindowModel mainWindowModel = container.GetExportedValue<MainWindowModel>();
    
        this.MainWindow = new MainWindow() { DataContext = mainWindowModel };
        this.MainWindow.Show();
      }
    }
    
    使用
    应用程序启动
    事件处理程序从App.xaml.cs初始化应用程序:

    interface IView
    {
    }
    
    interface IPluginSecondScreen : IView
    {
    }
    
    interface ICalculatorScreen : IView
    {
    }
    
    class PluginSecondScreen : UserControl, IPluginSecondScreen
    {
    }
    
    class CalculatorScreen : UserControl, ICalculatorScreen
    {
    }
    
    private void Run(object sender, StartupEventArgs e)
    {
      RegistrationBuilder builder = new RegistrationBuilder();
      builder.ForTypesDerivedFrom<IView>()
        .ExportInterfaces();
    
      builder.ForType<MainWindowModel>()
        .Export()
        .ImportProperties(
          propertyInfo => propertyInfo.Name.Equals(nameof(MainWindowModel.Plugins), StringComparison.OrdinalIgnoreCase) 
            || propertyInfo.Name.Equals(nameof(MainWindowModel.PluginView), StringComparison.OrdinalIgnoreCase));
    
      var catalog = new AggregateCatalog();
      catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "InternalShared.dll", builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginCalculator.dll", builder));
      catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginSecond.dll", builder));
    
      using (var container = new CompositionContainer(catalog))
      {    
        MainWindowModel mainWindowModel = container.GetExportedValue<MainWindowModel>();
    
        this.MainWindow = new MainWindow() { DataContext = mainWindowModel };
        this.MainWindow.Show();
      }
    }
    
    private void运行(对象发送方、StartupEventArgs e)
    {
    RegistrationBuilder=新的RegistrationBuilder();
    builder.ForTypesDerivedFrom()的
    .ExportInterfaces();
    builder.ForType()
    .出口()
    .进口物业(
    propertyInfo=>propertyInfo.Name.Equals(nameof(MainWindowModel.Plugins),StringComparison.OrdinalIgnoreCase)
    ||propertyInfo.Name.Equals(nameof(Ma