Caliburn Micro: связанные с плагинами вопросы для сценария на основе MEF - PullRequest
3 голосов
/ 03 июня 2011

У меня есть сценарий с приложением WPF, в котором размещаются некоторые представления (пользовательские элементы управления) со своими моделями представления, которые обнаруживаются в виде экспортируемых деталей MEF в папке плагинов.Приложение загружает свои данные вместе с файлом конфигурации, в котором также указывается, какие детали следует импортировать среди доступных.

Первый вопрос относится к загрузчику MEF: как я могу настроить его, чтобы он знал о папке плагинов?Я знаю о его SelectAssemblies переопределении, но он требует сборок, в то время как мой типичный подход - каталог каталогов MEF.Я не хотел бы использовать методы, такие как Assembly.LoadFrom для каждой библиотеки DLL, найденной в каталоге: для этого есть MEF (управление временем жизни и тому подобное).Итак, как я могу сделать что-то похожее на MEF AggregateCatalog , построенный из DirectoryCatalog в загрузчике?

Второй вопрос : раз у меня естьсписок виртуальных машин мне нужен, я хочу их создать.Некоторые из них требуют внедрения служб CM, таких как IEventAggregator или IWindowManager , так что они имеют соответствующий конструктор импорта, и поэтому мне требуется, чтобы CM создал их для меня: но мне нужно сделатьэто программно, поэтому я не могу просто использовать атрибут Import для свойства или импортирующего конструктора.

То же самое верно и для представлений: после того, как у меня есть виртуальные машины, мне нужен CM для их создания и установкисоответствующая виртуальная машина как их контекст данных;но я не могу использовать диспетчер окон, потому что я просто хочу получить их, а затем программно добавить их (они являются пользовательскими) в элемент управления с вкладками, который составляется по-разному в зависимости от конфигурации данных.

I'mиспользование MEF, потому что приложение ориентировано на плагины, и поэтому я могу придерживаться его ограничений при использовании в качестве IoC.Но я хотел бы использовать CM для создания экземпляров моих представлений и моделей представления (все они содержатся в нескольких библиотеках подключаемых модулей) и правильно связывать их.Может ли кто-нибудь дать некоторые подсказки или указать образцы или документацию по этому поводу?

Второе обновление , как и было обещано:):

Я, по сути, следую этим шагам:

  1. создать (используя MEF) необходимые виртуальные машины в соответствии с некоторой логикой приложения.Все виртуальные машины являются экспортом MEF, размещенным в нескольких плагинах в папке плагинов.

  2. для каждой виртуальной машины, вызов:

static private object LocateViewFor(object viewmodel)
{
  UIElement view = ViewLocator.LocateForModel(viewmodel, null, null);
    ViewModelBinder.Bind(viewmodel, view, null);
  return view;
}

Thisдолжен istantiate мои представления через CM, который также удовлетворит их импорт и свяжет каждое представление с его VM.Используется «стандартный» MefBootstrapper, модифицированный для WPF (см., Например, здесь ).В любом случае, это не работает и возвращает ноль.

Я должен сообщить загрузчику, где он может найти мой экспорт MEF.Они находятся в папке плагинов, и если бы я не использовал CM, я бы использовал MEF DirectoryCatalog для проверки его содержимого.Типичной точкой расширения для загрузчиков в CM является переопределение SelectAssemblies, которое требует от меня вернуть список объектов Assembly.Загрузка всех сборок из папки не вариант.Следуя предложению на приведенной выше странице, я мог бы сделать что-то вроде добавления метода в моем загрузчике:

private IEnumerable GetDirectoryCatalogs()
{
 return new ComposablePartCatalog[]
 {
 new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory)
 // TODO other plugins folders...
  };
}

И изменить его конфигурационный код следующим образом:

_container = new CompositionContainer(
  new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType()
  .Union(GetDirectoryCatalogs())));

Это эффективноКажется, что загружает необходимые сборки, как для MEF, но недостаточно «зарегистрировать» их в CM AssemblySource.Instance: фактически, я могу получить виртуальные машины через MEF, но когда я прошу CM получить соответствующее представление (либо с помощьюПриведенный выше метод или вызов IWindowManager.ShowDialog (myviewmodel, null)) Я получаю значение null из метода или (для второго примера) текстовое поле «placeholder», в котором говорится, что представление для моей виртуальной машины не может быть найдено.

Похоже, это связано с тем, что представление, как и модель представления, размещено в другой сборке, моем плагине MEF.Я гарантировал, что и представление, и модель представления совместно используют одно и то же пространство имен , а следуют соглашению об именовании типа SomeNamespace.SampleViewModel - SomeNamespace.SampleView;Кроме того, и представление, и модель представления экспортируются путем их украшения с помощью [Export] и являются производными от общих интерфейсов.Тем не менее, я не могу заставить CM работать должным образом при работе с внешними сборками.MEF работает нормально, со всеми его импортом и экспортом, но как только CM вводит уравнение, он не может сделать свое «волшебство» и найти представление из VM.

Любая подсказка?

1 Ответ

1 голос
/ 05 июня 2011

Я никогда ничего не делал с Caliburn Micro раньше, но использует ли он компонент CompositionInitializer для удовлетворения импорта?Если это так, вы можете использовать CompositionHost для ручной инициализации контейнера, используемого для удовлетворения импорта, например:

var catalog = new AggregateCatalog(
    new DirectoryCatalog("bin"),
    new DirectoryCatalog("Plugins"));

CompositionHost.Initialise(catalog);

При любых вызовах CompositionInitialiser.SatisfyImports(...) будет использоваться контейнер, созданный из созданных вами каталогов.

Если вы хотите программно создавать экземпляры экспорта, вам понадобится ссылка на сам фактический CompositionContainer.Но для этого нам нужен другой альтернативный способ инициализации композиции.Вы можете создать контейнер и хранить ссылку на него, например:

var catalog = new AggregateCatalog(
    new DirectoryCatalog("bin"),
    new DirectoryCatalog("Plugins"));
var container = new CompositionContainer(catalog);
CompositionHost.Initialise(container);

Container = container;

... где Container - статическая ссылка на ваш экземпляр CompositionContainer.Мы изменили вызов на CompositionHost, чтобы указать конкретный контейнер, который будет использовать CompositionInitializer, чтобы все по-прежнему работало правильно, но у нас есть контейнер, который мы можем использовать для создания конкретных экземпляров, например:

var viewModel = Container.GetExport<ISomeViewModel>();

Это помогает?

...