MEF2 & Caliburn.Micro - IWindowManager 和 IEventAggregator 没有导入到 ShellViewModel
MEF2 & Caliburn.Micro - IWindowManager and IEventAggregator are not importing to ShellViewModel
我无法让 MEF2 将 WindowManager 或 EventAggregator 导入我的 ShellViewModel。我自己的 Classes 似乎工作正常。
我已经将我的项目设置为使用 MEF2(System.ComponentModel.Composition 和 children)。我遵循 Customizing The Bootstrapper document to start as well as Tim Corey's From Zero to Proficient with MEF, and realized that these are MEF1. I did some reading, MEF 2 Preview Beginners Guide and Managed Extensibility Framework Improvements in .NET 4.5,用 RegistrationBuilder 替换了 CompositionBatch,并去掉了建议的 Class 和 属性 属性,以支持 RegistrationBuilder 的 Fluid API 来配置导入和导出。
当 ShellViewModel 尝试使用 _eventAggregator 时,我在 OnActivate 覆盖中收到 NullReferenceException。从未进行过进口。
如果我 运行 通过注释掉 OnActivate() 和 OnDeactivate(),它会启动并显示空白 window,因此它正在正确加载 shell。它只是没有导入任何依赖项。
下面是最简单的 Bootstrapper 和 ViewModel 来说明问题。
Bootstrapper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.Reflection;
using MEF2Test.ViewModels;
namespace MEF2Test
{
public class MefBootstrapper : BootstrapperBase
{
private CompositionContainer _container;
public MefBootstrapper()
{
Initialize();
}
protected override void Configure()
{
RegistrationBuilder cmBuilder = new RegistrationBuilder();
RegistrationBuilder cmpBuilder = new RegistrationBuilder();
RegistrationBuilder vmBuilder = new RegistrationBuilder();
cmBuilder.ForTypesDerivedFrom<IEventAggregator>().Export<IEventAggregator>();
cmpBuilder.ForTypesDerivedFrom<IWindowManager>().Export<IWindowManager>();
vmBuilder.ForTypesDerivedFrom<IShell>().Export<IShell>();
// These added based on a reference I read, to use ImportProperty
vmBuilder.ForTypesDerivedFrom<IShell>().ImportProperty<IEventAggregator>(x => x.EventAggregator);
vmBuilder.ForTypesDerivedFrom<IShell>().ImportProperty<IWindowManager>(x => x.WindowManager);
AggregateCatalog catalog = new AggregateCatalog();
AssemblyCatalog cmAssembly = new AssemblyCatalog(typeof(IEventAggregator).GetTypeInfo().Assembly, cmBuilder);
AssemblyCatalog cmpAssembly = new AssemblyCatalog(typeof(IWindowManager).GetTypeInfo().Assembly, cmpBuilder);
AssemblyCatalog vmAssembly = new AssemblyCatalog(typeof(MefBootstrapper).GetTypeInfo().Assembly, vmBuilder);
catalog.Catalogs.Add(cmAssembly);
catalog.Catalogs.Add(cmpAssembly);
catalog.Catalogs.Add(vmAssembly);
_container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] {
typeof(IWindowManager).GetTypeInfo().Assembly,
typeof(IEventAggregator).GetTypeInfo().Assembly,
typeof(MefBootstrapper).GetTypeInfo().Assembly
};
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = _container.GetExportedValues<object>(contract);
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}", contract));
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _container.GetExports<object>(AttributedModelServices.GetContractName(serviceType));
}
protected override void BuildUp(object instance)
{
_container.SatisfyImportsOnce(instance);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
}
ShellViewModel.cs
using Caliburn.Micro;
namespace MEF2Test.ViewModels
{
public class ShellViewModel : Screen, IShell
{
private IWindowManager _windowManager;
private IEventAggregator _eventAggregator;
public ShellViewModel()
{
}
protected override void OnActivate()
{
base.OnActivate();
_eventAggregator.Subscribe(this);
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
_eventAggregator.Unsubscribe(this);
}
// These 2 Properties added based on a reference I read, to use ImportProperty
public IEventAggregator EventAggregator
{
get { return _eventAggregator; }
set { _eventAggregator = value; }
}
public IWindowManager WindowManager
{
get { return _windowManager; }
set { _windowManager = value; }
}
}
public interface IShell
{
// These added based on a reference I read, to use ImportProperty
IEventAggregator EventAggregator { get; set; }
IWindowManager WindowManager { get; set; }
}
}
我想通了。出于某种原因,我必须使用:
ForType<ConcreteType>.ImportProperty<Interface>(x => x.PublicPropertyToSetInterface);
注册导入时。这使我的简单示例起作用,从而回答了我的问题。我的实际项目仍然存在
System.InvalidCastException: 'Unable to cast object of type 'System.Lazy`1[System.Object]' to type 'Caliburn.Micro.IWindowManager'.'
错误,但这可能是我在注册时遗漏或歪曲的内容。
我无法让 MEF2 将 WindowManager 或 EventAggregator 导入我的 ShellViewModel。我自己的 Classes 似乎工作正常。
我已经将我的项目设置为使用 MEF2(System.ComponentModel.Composition 和 children)。我遵循 Customizing The Bootstrapper document to start as well as Tim Corey's From Zero to Proficient with MEF, and realized that these are MEF1. I did some reading, MEF 2 Preview Beginners Guide and Managed Extensibility Framework Improvements in .NET 4.5,用 RegistrationBuilder 替换了 CompositionBatch,并去掉了建议的 Class 和 属性 属性,以支持 RegistrationBuilder 的 Fluid API 来配置导入和导出。
当 ShellViewModel 尝试使用 _eventAggregator 时,我在 OnActivate 覆盖中收到 NullReferenceException。从未进行过进口。
如果我 运行 通过注释掉 OnActivate() 和 OnDeactivate(),它会启动并显示空白 window,因此它正在正确加载 shell。它只是没有导入任何依赖项。
下面是最简单的 Bootstrapper 和 ViewModel 来说明问题。
Bootstrapper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Caliburn.Micro;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.Reflection;
using MEF2Test.ViewModels;
namespace MEF2Test
{
public class MefBootstrapper : BootstrapperBase
{
private CompositionContainer _container;
public MefBootstrapper()
{
Initialize();
}
protected override void Configure()
{
RegistrationBuilder cmBuilder = new RegistrationBuilder();
RegistrationBuilder cmpBuilder = new RegistrationBuilder();
RegistrationBuilder vmBuilder = new RegistrationBuilder();
cmBuilder.ForTypesDerivedFrom<IEventAggregator>().Export<IEventAggregator>();
cmpBuilder.ForTypesDerivedFrom<IWindowManager>().Export<IWindowManager>();
vmBuilder.ForTypesDerivedFrom<IShell>().Export<IShell>();
// These added based on a reference I read, to use ImportProperty
vmBuilder.ForTypesDerivedFrom<IShell>().ImportProperty<IEventAggregator>(x => x.EventAggregator);
vmBuilder.ForTypesDerivedFrom<IShell>().ImportProperty<IWindowManager>(x => x.WindowManager);
AggregateCatalog catalog = new AggregateCatalog();
AssemblyCatalog cmAssembly = new AssemblyCatalog(typeof(IEventAggregator).GetTypeInfo().Assembly, cmBuilder);
AssemblyCatalog cmpAssembly = new AssemblyCatalog(typeof(IWindowManager).GetTypeInfo().Assembly, cmpBuilder);
AssemblyCatalog vmAssembly = new AssemblyCatalog(typeof(MefBootstrapper).GetTypeInfo().Assembly, vmBuilder);
catalog.Catalogs.Add(cmAssembly);
catalog.Catalogs.Add(cmpAssembly);
catalog.Catalogs.Add(vmAssembly);
_container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe);
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] {
typeof(IWindowManager).GetTypeInfo().Assembly,
typeof(IEventAggregator).GetTypeInfo().Assembly,
typeof(MefBootstrapper).GetTypeInfo().Assembly
};
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = _container.GetExportedValues<object>(contract);
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}", contract));
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _container.GetExports<object>(AttributedModelServices.GetContractName(serviceType));
}
protected override void BuildUp(object instance)
{
_container.SatisfyImportsOnce(instance);
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
}
ShellViewModel.cs
using Caliburn.Micro;
namespace MEF2Test.ViewModels
{
public class ShellViewModel : Screen, IShell
{
private IWindowManager _windowManager;
private IEventAggregator _eventAggregator;
public ShellViewModel()
{
}
protected override void OnActivate()
{
base.OnActivate();
_eventAggregator.Subscribe(this);
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
_eventAggregator.Unsubscribe(this);
}
// These 2 Properties added based on a reference I read, to use ImportProperty
public IEventAggregator EventAggregator
{
get { return _eventAggregator; }
set { _eventAggregator = value; }
}
public IWindowManager WindowManager
{
get { return _windowManager; }
set { _windowManager = value; }
}
}
public interface IShell
{
// These added based on a reference I read, to use ImportProperty
IEventAggregator EventAggregator { get; set; }
IWindowManager WindowManager { get; set; }
}
}
我想通了。出于某种原因,我必须使用:
ForType<ConcreteType>.ImportProperty<Interface>(x => x.PublicPropertyToSetInterface);
注册导入时。这使我的简单示例起作用,从而回答了我的问题。我的实际项目仍然存在
System.InvalidCastException: 'Unable to cast object of type 'System.Lazy`1[System.Object]' to type 'Caliburn.Micro.IWindowManager'.'
错误,但这可能是我在注册时遗漏或歪曲的内容。