MEF2 & Caliburn.Micro - IWindowManager и IEventAggregator не импортируются в ShellViewModel - PullRequest
0 голосов
/ 01 апреля 2019

Я не могу заставить MEF2 импортировать WindowManager или EventAggregator в мою ShellViewModel.Кажется, все мои собственные классы работают нормально.

Я настроил свой проект для использования MEF2 (System.ComponentModel.Composition и дочерние элементы).Я следовал за настройкой документа Bootstrapper для запуска, а также за Тима Кори с «Zero to Proficient» с MEF и понял, что это MEF1.Я немного почитал Руководство для начинающих по MEF 2 Preview и Улучшения в Managed Extensibility Framework .NET 4.5 , заменил CompositionBatch на RegistrationBuilder и избавился от предложенных атрибутов класса и свойства, чтобы отдать предпочтениеFluid API RegistrationBuilder для настройки импорта и экспорта.

Я получаю исключение NullReferenceException в переопределении OnActivate в ShellViewModel, когда он пытается использовать _eventAggregator.Импорт никогда не выполнялся.

Если я запустил это, закомментировав OnActivate () и OnDeactivate (), он запустится и отобразит пустое окно, поэтому он правильно загружает оболочку.Он просто не импортирует никаких зависимостей.

Вот самые простые 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; }
    }
}

1 Ответ

0 голосов
/ 02 апреля 2019

Я понял это. По какой-то причине я должен использовать:

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'.'

ошибка, но это, вероятно, то, что я пропустил или исказил в своих регистрациях.

...