12

我正在学习 Caliburn Micro 并尝试使用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 解决方案。

我想念什么?

4

2 回答 2

10

devdigital 是正确的。他说

重要的是其他引导程序配置。

这是完全正确的。

如果您要使用 DI (这SimpleContainer对您有用),那么您必须覆盖引导程序中的GetInstance(), GetAllInstances(), BuildUp()方法,因为 CM 在需要容器中的某些内容时会调用这些方法。

你的情况是这样的:

  1. CM 尝试显示您的MainViewModel,因为您在 Bootstrapper 中将其指定为通用参数。
  2. CM 注意到您MainViewModel有一个构造函数,该构造函数采用IEventAggregator.
  3. CM 调用GetInstance()以获取注册为IEventAggregator.
  4. CM 发现您尚未覆盖GetInstance(),因此它尝试创建MainViewModelusing的实例Activator.CreateInstance()
  5. 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);
        }

    }
于 2013-07-23T11:55:15.037 回答
9
// ... Other Bootstrapper Config

重要的是另一个引导程序配置。

最好的选择是通过Caliburn.Micro.Start NuGet 包安装 Caliburn.Micro,并查看提供的引导程序,它也使用SimpleContainerCaliburn.Micro 提供的引导程序。

这是完整的:

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>();
     }
}
于 2013-07-23T07:58:24.500 回答