Pull to refresh

Руководство разработчика Prism — часть 2, инициализация приложений Prism

Reading time 11 min
Views 31K
Original author: microsoft patterns & practices
Оглавление
  1. Введение
  2. Инициализация приложений Prism
  3. Управление зависимостями между компонентами
  4. Разработка модульных приложений
  5. Реализация паттерна MVVM
  6. Продвинутые сценарии MVVM
  7. Создание пользовательского интерфейса
    1. Рекомендации по разработке пользовательского интерфейса
  8. Навигация
    1. Навигация на основе представлений (View-Based Navigation)
  9. Взаимодействие между слабо связанными компонентами

Эта глава рассказывает о том, что нужно сделать для загрузки приложения Prism. Приложение Prism требует регистрации и конфигурации компонентов во время запуска – этот процесс известен как bootstrapping.

Что такое загрузчик (Bootstrapper)


Загрузчик является классом, ответственным за инициализацию приложения, созданного с использованием библиотеки Prism. При использовании загрузчика вы получаете больший контроль над тем, как компоненты библиотеки Prism создаются и соединяются при запуске вашего приложения. Библиотека Prism включает абстрактный базовый класс загрузчика, который может быть специализирован для использования с любым контейнером. Многие из методов в классах загрузчиков являются виртуальными. Можно переопределять эти методы для предоставления собственной их реализации.

Основные этапы процесса загрузки.

Библиотека Prism предоставляет некоторые дополнительные базовые классы, унаследованные от класса Bootstrapper, имеющие реализации по умолчанию, которые подходят для большинства приложений. Остаётся только добавить реализацию создания и инициализации оболочки приложения.

Внедрение зависимостей

Приложения, созданные с использованием библиотеки Prism, полагаются на механизм внедрения зависимостей, обеспеченный контейнером. Библиотека предоставляет сборки, работающие с Unity Application Block (Unity) или Managed Extensibility Framework (MEF), и позволяет использовать другие DI контейнеры. Частью процесса начальной загрузки является конфигурирование контейнера и регистрация в нём необходимых типов.

Библиотека Prism включает классы UnityBootstrapper и MefBootstrapper, реализующие большую часть функциональности, необходимой для использования как Unity, так и MEF в качестве DI контейнера. В дополнение к этапам, показанным на предыдущей иллюстрации, каждый загрузчик добавляет некоторые шаги, специфичные для используемого контейнера.

Создание оболочки

В традиционном WPF приложении, в файле App.xaml определяется стартовый URI, по которому при загрузке приложения определяется, какое окно является корневым. В приложении Silverlight свойство RootVisual приложения устанавливается в code behind файла App.xaml. В приложении, созданном с использованием библиотеки Prism, загрузчик обязан сам создать оболочку или главное окно. Это сделано из-за того, что оболочка полагается на службы, такие как менеджер регионов, который должны быть зарегистрированы до того, как оболочка будет создана и выведена на экран.

Ключевые решения


После того, как вы решите использовать библиотеку Prism в своем приложении, нужно будет подумать над следующим:
  • Вы должны будете решить, будете ли вы использовать MEF, Unity, или другой DI контейнер в вашем приложении. Это определит, какой класс загрузчика вам следует использовать, или должны ли вы будете создавать свой загрузчик для выбранного контейнера.
  • Следует подумать о специализированных службах, которые вы будете использовать в своем приложении. Они должны быть также зарегистрированы в контейнере.
  • Определите, удовлетворяет ли встроенная служба журналирования ваши потребности, или вы должны будете создать и зарегистрировать другую службу.
  • Определите, как модули будут обнаружены приложением: через явные объявления в коде, через атрибуты на модулях, обнаруженных после сканирование каталога файловой системы, через конфигурационный файл, или через XAML.

Далее рассмотрим эти пункты в деталях.

Базовые сценарии


Создание последовательности загрузки является важной частью создание вашего Prism приложения. Этот раздел описывает, как создать загрузчик и настроить его так, чтобы создать оболочку, сконфигурировать DI контейнер и службы уровня приложения и то, как загрузить и инициализировать модули.

Создание загрузчика для вашего приложения

Если вы выберете Unity или MEF, то создать загрузчик будет относительно просто. Необходимо создать класс, унаследованный от MefBootstrapper или UnityBootstrapper и реализовать метод CreateShell. Дополнительно, можно переопределить метод InitializeShell для специфической инициализации класса оболочки.

Реализация метода CreateShell

Метод CreateShell позволяет разработчику определить высокоуровневое окно для приложения Prism. Оболочкой обычно является MainWindow или MainPage, в случае с Silverlight. Реализуйте этот метод, возвратив экземпляр класса оболочки вашего приложения. В приложении Prism можно как создать объект оболочки, так и получить его из контейнера, в зависимости от требований вашего приложения.

Пример использования ServiceLocator для получения объекта оболочки даётся в следующем примере кода.

protected override DependencyObject CreateShell()
{
    return ServiceLocator.Current.GetInstance<Shell>();
}

Заметка
Вы будете часто видеть, что для получения экземпляров типов вместо определенного контейнера внедрения зависимости используется ServiceLocator. ServiceLocator реализован так, что перенаправляет вызовы контейнеру, поэтому его использование является хорошим выбором для написания кода, не зависящего от выбранного контейнера. Можно также ссылаться и использовать непосредственно контейнер, а не ServiceLocator.

Реализация метода InitializeShell

После того, как вы создали оболочку, вы, возможно, должны будете выполнить шаги инициализации, чтобы гарантировать, что оболочка готова для вывода на экран. В зависимости от того, пишете ли вы приложение WPF или Silverlight, реализации метода InitializeShell может изменяться. Для приложений Silverlight вы должны установить оболочку как визуальный корень приложения, как показано ниже.

protected override void InitializeShell()
{
    Application.Current.RootVisual = Shell;
}

Для приложений WPF необходимо создать объект оболочки приложения и установить его как главное окно приложения (взято из Modularity QuickStarts для WPF).

protected override void InitializeShell()
{
    Application.Current.MainWindow = Shell;
    Application.Current.MainWindow.Show();
}

Базовая реализация InitializeShell ничего не делает. Безопасно не вызвать реализацию базового класса.

Создание и конфигурирование каталога модулей

Если вы создаёте модульное приложение, то вы должны будете создать и сконфигурировать каталог модулей. Prism использует конкретный экземпляр IModuleCatalog для отслеживания того, какие модули доступны приложению, какие модули, возможно, должны быть загружены и где модули находятся.

Класс Bootstrapper предоставляет защищенное свойство ModuleCatalog для ссылки на каталог, а также базовую реализацию виртуального метода CreateModuleCatalog. Базовая реализация возвращает новый экземпляр ModuleCatalog. Однако, этот метод может быть переопределён, чтобы предоставить другой экземпляр каталога модулей, как показано в следующем примере кода из QuickStartBootstrapper в Modularity with MEF для Silverlight QuickStart.

protected override IModuleCatalog CreateModuleCatalog()
{
    // When using MEF, the existing Prism ModuleCatalog is still
    // the place to configure modules via configuration files.
    return ModuleCatalog.CreateFromXaml(new Uri(
                     "/ModularityWithMef.Silverlight;component/ModulesCatalog.xaml",
                     UriKind.Relative));
}

В обоих классах UnityBootstrapper и MefBootstrapper метод Run вызывает метод CreateModuleCatalog и затем устанавливает свойство ModuleCatalog класса, используя возвращенное значение. Если вы переопределяете этот метод, нет необходимости вызвать реализацию базового класса, потому что вы заменяете предоставленную функциональность. Для получения дополнительной информации о модульности, смотрите главу 4, «Modular Application Development».

Создание и настройка DI контейнера

Контейнеры играют ключевую роль в приложении, созданном с использованием библиотеки Prism. И библиотека Prism, и приложения, созданные с её использованием, зависят от DI контейнера, необходимого для внедрения требуемых зависимостей и служб. Во время фазы конфигурирования контейнера, в нём регистрируются некоторые базовые службы. В дополнение к этим службам, у вас могут быть собственные специализированные службы, предоставляющие дополнительную функциональность, влияющую на процесс композиции.

Базовые службы

В следующей таблице показаны базовые неспециализированные службы библиотеки Prism.
Интерфейс. Описание.
IModuleManager, менеджер модулей Определяет интерфейс для службы, который получает и инициализирует модули приложения.
IModuleCatalog, каталог модулей Содержит метаданные о модулях в приложении. Библиотека Prism предоставляет несколько различных каталогов.
IModuleInitializer, инициализатор модулей Инициализирует модули.
IRegionManager, менеджер регионов Регистрирует и получает регионы, являющиеся визуальными контейнерами для разметки.
IEventAggregator, агрегатор событий Коллекция событий, слабо связанных между издателем и подписчиком.
ILoggerFacade Обертка для механизма журналирования. Таким образом, можно выбрать свой собственный механизм журналирования. Stock Trader Reference Implementation (Stock Trader RI) пользуется Enterprise Library Logging Application Block, через класс EnterpriseLibraryLoggerAdapter, как пример того, как можно использовать свой собственный логгер. Служба журналирования регистрируется в контейнере в методе Run загрузчика, используя значение, возвращенное методом CreateLogger. Регистрация другого логгера в контейнере не будет работать, вместо этого переопределите метод CreateLogger в загрузчике.
IServiceLocator Позволяет библиотеке Prism получать доступ к контейнеру. Может оказаться полезным, если вы захотите настроить или расширить библиотеку.

Специализированные службы

Следующая таблица приводит специализированные службы, используемые в Stock Trader RI. Они могут использоваться в качестве примера для понимания того, какие службы могут быть в вашем приложении.
Служба в Stock Trader RI. Описание.
IMarketFeedService Предоставляет (подставные) данные рынка в реальном времени. PositionSummaryPresentationModel обновляет экран позиций, основываясь на уведомлениях, полученных от этой службы.
IMarketHistoryService Предоставляет историю данных рынка, используемую для вывода на экран линии тренда для выбранного фонда.
IAccountPositionService Предоставляет список фондов в портфеле.
IOrdersService Содержит отправленные заказы о покупке/продаже.
INewsFeedService Предоставляет список новостных сообщений для выбранного фонда.
IWatchListService Определяет, когда новый элемент добавляется в список отслеживаемых элементов.

Есть два загрузчика производных от класса Bootstrapper, доступные в Prism, UnityBootstrapper и MefBootstrapper. Создание и конфигурирование других контейнеров включает похожие шаги, реализованные немного по-другому.

Создание и конфигурирование контейнера в UnityBootstrapper

Метод CreateContainer класса UnityBootstrapper просто создает и возвращает новый экземпляр UnityContainer. В большинстве случаев менять эту функциональность не нужно. Однако, метод является виртуальным, предоставляя необходимую гибкость. После того, как контейнер создан, он, вероятно, должен быть соответственно сконфигурирован. Реализация ConfigureContainer в UnityBootstrapper регистрирует базовые службы Prism по умолчанию, как показано ниже.
Заметка
Примерно так же модуль регистрирует свои службы в методе Initialize.

protected virtual void ConfigureContainer()
{
    ...
    if (useDefaultConfiguration)
 {
    RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
    RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true);
    RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true);
    RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true);
    RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);
    RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);
    RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);
    RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);
    }
}

Метод RegisterTypeIfMissing загрузчика определяет, была ли служба уже зарегистрирована, что предотвращает от их повторной регистрации. Это позволяет вам переопределять регистрацию по умолчанию через конфигурацию. Можно также выключить регистрацию любых служб по умолчанию, чтобы сделать это, используйте перегруженный метод Bootstrapper.Run, передавая в него значение false. Можно также переопределить метод ConfigureContainer и отключить службы, которые вы не хотите использовать, такие как агрегатор событий.
Заметка
Если вы отключите регистрации по умолчанию, вам будет нужно вручную зарегистрировать необходимые службы.

Чтобы расширить поведение по умолчанию ConfigureContainer, просто добавьте переопределение к загрузчику своего приложения и дополнительно вызовите базовую реализацию, как показано в следующем коде от QuickStartBootstrapper из Modularity for WPF (with Unity) QuickStart. Эта реализация вызывает реализацию базового класса, регистрирует тип ModuleTracker как конкретную реализацию IModuleTracker, и регистрирует callbackLogger как синглтон экземпляра CallbackLogger, идущего вместе с Unity.

protected override void ConfigureContainer()
{
    base.ConfigureContainer();

    this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true);
    this.Container.RegisterInstance<CallbackLogger>(this.callbackLogger);
}

Создание и настройка контейнера в MefBootstrapper

Метод CreateContainer класса MefBootstrapper делает несколько вещей. Во-первых, он создаёт AssemblyCatalog и CatalogExportProvider. CatalogExportProvider позволяет сборке MefExtensions обеспечить экспорт по умолчанию для типов Prism и также позволяет переопределять регистрацию типа по умолчанию. Затем CreateContainer создает и возвращает новый экземпляр CompositionContainer, используя CatalogExportProvider. В большинстве случаев, вам не нужно будет изменить эту функциональность. Однако, метод является виртуальным, предоставляя необходимую гибкость.
Заметка
В Silverlight, из-за ограничений безопасности, нельзя получить сборку, используя тип. Вместо этого Prism использует другой метод, который использует метод Assembly.GetCallingAssembly.

После того, как контейнер будет создан, он должен быть сконфигурирован для вашего приложения. Реализация ConfigureContainer в MefBootstrapper регистрирует много базовых служб Prism по умолчанию, как показано в следующем примере кода. Если вы переопределяете этот метод, подумайте, следует ли вызвать реализацию базового класса, чтобы зарегистрировать базовые службы Prism, или вы предоставите их в своей реализации.

protected virtual void ConfigureContainer()
{
    this.RegisterBootstrapperProvidedTypes();
}

protected virtual void RegisterBootstrapperProvidedTypes()
{
    this.Container.ComposeExportedValue<ILoggerFacade>(this.Logger);
    this.Container.ComposeExportedValue<IModuleCatalog>(this.ModuleCatalog);
    this.Container.ComposeExportedValue<IServiceLocator>(new MefServiceLocatorAdapter(this.Container));
    this.Container.ComposeExportedValue<AggregateCatalog>(this.AggregateCatalog);
}

Заметка
В MefBootstrapper базовые службы Prism добавляются к контейнеру как синглeтоны, таким образом, они могут быть получены через контейнер повсюду в приложении.

В дополнение к предоставлению методов CreateContainer и ConfigureContainer, MefBootstrapper также предоставляет два метода для создания и конфигурирования AggregateCatalog, используемый MEF. Метод CreateAggregateCatalog просто создает и возвращает объект AggregateCatalog. Как другие методы в MefBootstrapper, CreateAggregateCatalog является виртуальным и может быть переопределен в случае необходимости. Метод ConfigureAggregateCatalog позволяет вам добавлять регистрацию типа к AggregateCatalog принудительно. Например, QuickStartBootstrapper от the Modularity with MEF for Silverlight QuickStart явно добавляет ModuleA и ModuleC к AggregateCatalog, как показано ниже.

protected override void ConfigureAggregateCatalog()
{
    base.ConfigureAggregateCatalog();
    // Add this assembly to export ModuleTracker
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(QuickStartBootstrapper).Assembly));
    // Module A is referenced in in the project and directly in code.
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleA.ModuleA).Assembly));

    // Module C is referenced in in the project and directly in code.
    this.AggregateCatalog.Catalogs.Add(
                 new AssemblyCatalog(typeof(ModuleC.ModuleC).Assembly));
}

Дополнительная информация


Для получения дополнительной информации про MEF, AggregateCatalog, и AssemblyCatalog, смотрите «Managed Extensibility Framework Overview» на MSDN: http://msdn.microsoft.com/en-us/library/dd460648.aspx.
Tags:
Hubs:
+4
Comments 0
Comments Leave a comment

Articles