带有MEF2的WPF MvvM中的插件
我已经尝试了以下非常好的教程来迁移到MEF2,但是由于某些原因,这些部件没有显示在目录中。从MEF2开始,我想使用API配置(RegistrationBuilder类)(这里是一个示例:),也许有人知道如何将MEF2正确地应用到教程中。多谢各位 下面是解决方案的概述: 在MainViewModel.cs中,我还不知道如何将导入集成到带有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
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
不再需要它们。
我检查了你的尝试。需要改进的几点
get
和set
添加到PluginView
和Plugins
的定义中MainWindowModel
中的所有属性中删除Import
属性李>
IView
和一个导入(基数)。您应该导入一组具体类型,只注册一个具体类型,或者为每个具体类型引入一个专用接口(例如PluginSecondScreen
和ICalculatorScreen
),其中每个接口继承共享接口(例如IView
)合成容器
SetCreationPolicy(CreationPolicy.Any)
与CreationPolicy一样是多余的。Any
是默认值,通常默认为CreationPolicy.Shared
字符串
文字。改用nameof
:导入属性(pi=>pi.Name==“插件”)
应该是:
ImportProperties(pi=>pi.Name==nameof(MainWindowModel.Plugins)
。这使得重构更加容易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