Не удалось выполнить инжекцию микроструктуры Caliburn

Я изучаю 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 в ViewModel с Caliburn Micro), но он просто ничего не сказал, почему CM не вызывает конструктор с инъекцией.

Я также проверил решение выборки CM, но использует MEF в качестве решения DI.

Что мне не хватает?

Ответ 1

// ... Other Bootstrapper Config

Это важная конфигурация другого загрузочного файла.

Лучшим вариантом является установка Caliburn.Micro с помощью пакета Caliburn.Micro.Start NuGet и ознакомление с предоставленным загрузчиком, который также использует предоставленный SimpleContainer по Caliburn.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>();
     }
}

Ответ 2

devdigital правильный. Он сказал

важна другая конфигурация загрузчика.

Это абсолютно правильно.

Если вы собираетесь использовать DI (который SimpleContainer делает для вас), вы должны переопределять методы GetInstance(), GetAllInstances(), BuildUp() в вашем загрузчике, потому что CM вызывает эти методы, когда он хочет что-то из контейнера.

То, что происходит в вашей ситуации, выглядит следующим образом:

  • CM пытается показать ваш MainViewModel, потому что вы указали его как общий параметр в Bootstrapper.
  • CM замечает, что ваш MainViewModel имеет один конструктор, который принимает IEventAggregator.
  • CM вызывает GetInstance(), чтобы получить то, что зарегистрировано как IEventAggregator.
  • CM показывает, что вы не переопределили 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);
        }

    }