我正在学习Caliburn Micro,并尝试使用official site中的EventAggregator
。
然而,我得到了一个例外
“没有为此对象定义无参数构造函数。”
消息本身很清楚,但示例中也没有包含无参数构造函数。如果我添加一个,则不会触发带参数的构造函数,并且仍未正确注入IEventAggregator
。
在添加无参数构造函数之后,这是我的发布者VM(没有它,将抛出异常):
public MainViewModel() { }
public MainViewModel(IEventAggregator ea) : this()
{
eventAggregator = ea;
}
这是我正在使用的引导程序:
public class AppBootstrapper : Bootstrapper<MainViewModel>
{
private readonly SimpleContainer container = new SimpleContainer();
protected override void Configure()
{
container.Singleton<IEventAggregator, EventAggregator>();
}
}
以下是CM的例子:
// Creating the EventAggregator as a singleton.
public class Bootstrapper : BootstrapperBase {
private readonly SimpleContainer _container =
new SimpleContainer();
// ... Other Bootstrapper Config
protected override void Configure(){
_container.Singleton<IEventAggregator, EventAggregator>();
}
// ... Other Bootstrapper Config
}
// Acquiring the EventAggregator in a viewModel.
public class FooViewModel {
private readonly IEventAggregator _eventAggregator;
public FooViewModel(IEventAggregator eventAggregator) {
_eventAggregator = eventAggregator;
}
}
我检查过这篇文章(Inject EventAggregator into ViewModel with Caliburn Micro),但它没有说明为什么CM不会通过注入来调用构造函数。
我还检查了CM的样品溶液,但它使用MEF作为DI溶液。
我想念什么?
答案 0 :(得分:9)
// ... Other Bootstrapper Config
这是另一个重要的bootstrapper配置。
最好的选择是通过Caliburn.Micro.Start NuGet包安装Caliburn.Micro,并查看提供的引导程序,它也使用Caliburn.Micro提供的SimpleContainer
。
这里是完整的:
public class AppBootstrapper : BootstrapperBase
{
SimpleContainer container;
public AppBootstrapper()
{
Start();
}
protected override void Configure()
{
container = new SimpleContainer();
container.Singleton<IWindowManager, WindowManager>();
container.Singleton<IEventAggregator, EventAggregator>();
container.PerRequest<IShell, ShellViewModel>();
}
protected override object GetInstance(Type service, string key)
{
var instance = container.GetInstance(service, key);
if (instance != null)
return instance;
throw new InvalidOperationException("Could not locate any instances.");
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
container.BuildUp(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
答案 1 :(得分:9)
devdigital是正确的。他说
另一个重要的引导程序配置。
这是完全正确的。
如果您要使用DI (SimpleContainer
为您执行此操作),那么必须覆盖引导程序中的GetInstance(), GetAllInstances(), BuildUp()
方法,因为CM在需要容器中的内容时调用这些方法。
你的情况如下:
MainViewModel
,因为您已将其指定为Bootstrapper中的通用参数。MainViewModel
有一个带IEventAggregator
的构造函数。GetInstance()
以获取注册为IEventAggregator
的任何内容。GetInstance()
,因此它尝试使用MainViewModel
创建Activator.CreateInstance()
的实例。Activator.CreateInstance()
不知道如何创建IEventAggregator
,因此它会抛出异常(您正在获得的那个)。要解决所有这些问题,你必须覆盖我告诉你的方法。您不需要安装Nuget Caliburn.Start软件包(如果您不喜欢打字,可以使用它,并且想保存一些按键)。
基本上,您的最终解决方案应如下所示:
public class Bootstrapper : Bootstrapper<MainViewModel>
{
private readonly SimpleContainer _container = new SimpleContainer();
protected override void Configure()
{
_container.Instance<IWindowManager>(new WindowManager());
_container.Singleton<IEventAggregator, EventAggregator>();
_container.PerRequest<MainViewModel>();
}
protected override object GetInstance(Type service, string key)
{
return _container.GetInstance(service, key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
}