Я проверил вашу попытку. Несколько моментов, которые нуждаются в улучшении.
- Обычно вы должны сконфигурировать контейнер в центральном расположении, обычно в точке входа приложения при запуске, например, внутри метода App.xaml.cs. Класс никогда не создает свой собственный контейнер для импорта своих зависимостей. Если это необходимо, рассмотрите возможность импорта
ExportFactory<TImport>
( никогда обход вокруг контейнера). - Вы должны импортировать зависимости либо через конструктор (рекомендуется), либо свойства и не поля . Поэтому вам необходимо добавить
get
и set
к определениям PluginView
и Plugins
. - . Вы должны использовать либо аннотационное разрешение зависимостей, либо API. Не смешивай это. Поэтому вы должны удалить атрибут
Import
из всех свойств MainWindowModel
. - Вы не можете иметь несколько реализаций интерфейса, например,
IView
и один импорт (количество элементов). Вам следует либо импортировать коллекцию конкретных типов, зарегистрировать только один конкретный тип или ввести специализированный интерфейс для каждого конкретного типа (например, PluginSecondScreen
и ICalculatorScreen
), где каждый интерфейс наследует общий интерфейс (например, IView
). - Не забудьте утилизировать
CompositionContainer
после завершения инициализации. SetCreationPolicy(CreationPolicy.Any)
является избыточным, поскольку CreationPolicy.Any
является значением по умолчанию, которое обычно по умолчанию равно CreationPolicy.Shared
. - Попробуйте использовать интерфейсы везде
- Избегайте литералов
string
при использовании класса или члена класса или имен типов. Используйте nameof
вместо:
ImportProperties(pi => pi.Name == "Plugins")
должно быть:
ImportProperties(pi => pi.Name == nameof(MainWindowModel.Plugins)
. Это значительно упрощает рефакторинг.
MainWindowModel.cs
class MainWindowModel
{
// Import a unique matching type or import a collection of all matching types (see below).
// Alternatively let the property return IView and initialize it form the constructor,
// by selecting an instance from the `Plugins` property.
public IPluginSecondScreen PluginView { get; set; }
// Import many (implicit)
public IEnumerable<Lazy<IView>> Plugins { get; set; }
}
Интерфейсы IView
и специализации для создания уникальных типов:
interface IView
{
}
interface IPluginSecondScreen : IView
{
}
interface ICalculatorScreen : IView
{
}
Реализации интерфейса:
class PluginSecondScreen : UserControl, IPluginSecondScreen
{
}
class CalculatorScreen : UserControl, ICalculatorScreen
{
}
Инициализировать приложение из App.xaml.cs с помощью обработчика событий Application.Startup
:
private void Run(object sender, StartupEventArgs e)
{
RegistrationBuilder builder = new RegistrationBuilder();
builder.ForTypesDerivedFrom<IView>()
.ExportInterfaces();
builder.ForType<MainWindowModel>()
.Export()
.ImportProperties(
propertyInfo => propertyInfo.Name.Equals(nameof(MainWindowModel.Plugins), StringComparison.OrdinalIgnoreCase)
|| propertyInfo.Name.Equals(nameof(MainWindowModel.PluginView), StringComparison.OrdinalIgnoreCase));
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder));
catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "InternalShared.dll", builder));
catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginCalculator.dll", builder));
catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory, "PluginSecond.dll", builder));
using (var container = new CompositionContainer(catalog))
{
MainWindowModel mainWindowModel = container.GetExportedValue<MainWindowModel>();
this.MainWindow = new MainWindow() { DataContext = mainWindowModel };
this.MainWindow.Show();
}
}