ПРОГРАММИРОВАНИЕ16 августа
Начало MVVM и внедрение зависимостей Часть 1
Контейнер — это объект, который поддерживает все зависимости, которые могут быть разрешены в любом месте приложения. Сюда могут входить экземпляры и синглтоны, которые остаются в памяти на весь срок службы приложения. А также сопоставления реализации, которые создаются во время внедрения.
В App.xaml.cs вам нужно будет создать новый код для создания контейнера и регистрации зависимостей. Прямо сейчас мы просто создадим контейнер и завершим процесс регистрации.
Добавьте следующий код после конструктора:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public sealed partial class App : Application { public App() { InitializeComponent(); Container = ConfigureDependencyInjection(); } public IServiceProvider Container { get ; } IServiceProvider ConfigureDependencyInjection() { throw new NotImplementedException(); } } |
Уже в базовой библиотеке .NET есть класс IServiceProvider , это версия контейнера .NET, которая используется в библиотеке сообщества. Этот интерфейс обеспечивает отличное взаимодействие в экосистеме .NET. Для нашей реализации на платформе Uno это не имеет большого значения.
Теперь давайте продолжим и создадим экземпляр нашего контейнера.
1
2
3
4
5
6
7
8
9
10
|
IServiceProvider ConfigureDependencyInjection() { // Create new service collection which generates the IServiceProvider var serviceCollection = new ServiceCollection(); // TODO - Register dependencies // Build the IServiceProvider and return it return serviceCollection.BuildServiceProvider(); } |
Как только мы создадим наши зависимости, мы вернемся к процессу регистрации. На данный момент наш Контейнер создается правильно при запуске приложения.
В этом примере мы собираемся создать простой интерфейс (контракт) — отношения реализации со службой сообщений. Цель этого класса — получить сообщение для нашей MainViewModel по запросу.
Обычно я помещаю такие службы в их собственную папку « Службы » или « Менеджеры », вы даже можете начать создавать новый проект, чтобы еще больше отделить эти объекты от вашего общего кода пользовательского интерфейса.
Начнем с определения интерфейса IMessageService (контракта)
1
2
3
4
|
public interface IMessageService { string GetMessage(); } |
Как только интерфейс (контракт) определен, мы можем реализовать этот код в конкретном MessageService.
1
2
3
4
5
6
7
|
public class MessageService : IMessageService { public string GetMessage() { return "Hello from Message Service & Dependency Injection" ; } } |
Теперь, когда мы определили наш MessageService, пришло время зарегистрировать его в Container . Давайте продолжим с того места, где остановились в коде создания контейнера App.xaml.cs. Найдите наш комментарий TODO и замените его оператором регистрации, который определяет сопоставление между IMessageService и MessageService.
1
|
serviceCollection.AddTransient<IMessageService, MessageService>(); |
При регистрации сервисов в Контейнере существует концепция, называемая управлением жизненным циклом, которая сообщает Контейнеру , как должна быть зарегистрирована зависимость этого объекта. Это позволяет регистрировать экземпляры и синглтоны, которые остаются в памяти на весь жизненный цикл контейнера . Это также позволяет вам регистрировать зависимости, которые создаются по мере необходимости.
Собрав все вместе, наш окончательный код будет выглядеть так:
1
2
3
4
5
6
7
8
9
10
11
|
IServiceProvider ConfigureDependencyInjection() { // Create new service collection which generates the IServiceProvider var serviceCollection = new ServiceCollection(); // Register the MessageService with the container serviceCollection.AddTransient<IMessageService, MessageService>(); // Build the IServiceProvider and return it return serviceCollection.BuildServiceProvider(); } |
Теперь мы можем внедрить MessageService в MainViewModel и обновить свойство Message. Давайте разобьем это на 2 части:
Внедрение конструктора
Теперь мы можем предоставить параметр конструктора для MainViewModel IMessageService , это будет разрешено на следующем шаге. А пока давайте просто предположим, что он внедряется, и мы должны сохранить его в нашу ViewModel.
Я предпочитаю создавать защищенные свойства для своих зависимостей, так как это обеспечивает отличные точки расширения для других объектов, которые наследуются от него. Давайте определим, как это работает в коде:
1
2
3
4
5
6
7
8
9
10
11
|
public class MainViewModel { protected IMessageService MessageService { get ; } public MainViewModel(IMessageService messageService) { MessageService = MessageService; } // omitted code } |
Использование службы сообщений
Далее в нашем коде давайте обновим использование свойства Message, чтобы вместо этого возвращались данные из нашего MessageService . Это позволит MainViewModel отображать любые данные, предоставляемые службой, отделяя MainViewModel от любых правил уровня службы.
1
|
public string Message { get => MessageService.GetMessage(); } |
Наш окончательный завершенный класс будет выглядеть так:
1
2
3
4
5
6
7
8
9
10
11
|
public class MainViewModel { protected IMessageService MessageService { get ; } public MainViewModel(IMessageService messageService) { MessageService = MessageService; } public string Message { get => MessageService.GetMessage(); } } |
Перед созданием решения необходимо выполнить один последний шаг: необходимо правильно разрешить MainViewModel и внедрить зависимости. Существует отличная служебная функция под названием ActivatorUtils , которая использует IServiceProvider для создания экземпляра объекта и ввода параметров в конструктор.
Перейдите в свой код для MainPage.xaml.cs и добавьте следующую инструкцию, где вы создаете экземпляр DataContext. Ваш заполненный файл MainPage.xaml.cs должен выглядеть следующим образом.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public sealed partial class MainPage : Page { public MainPage() { this .InitializeComponent(); // Get a local instance of the container var container = ((App)App.Current).Container; // Request an instance of the ViewModel and set it to the DataContext DataContext = ActivatorUtilities.GetServiceOrCreateInstance(container, typeof (MainViewModel)); } } |
На этом этапе вы должны быть в состоянии создать и запустить свое приложение. Сообщение, напечатанное на экране, должно быть строкой, жестко запрограммированной в MessageService . Вот скриншот того, как окончательное решение должно выглядеть на UWP.
Поскольку платформа Uno является кроссплатформенной, этот код будет работать на разных платформах.
В этой статье рассматривается множество тем, посвященных созданию простого приложения MVVM, в котором используются передовые методы внедрения зависимостей. Если вы заблудились по пути или вам проще изучить пример кода, перейдите по ссылке на github ниже и загрузите весь код из этой статьи.
Диалог в WPF C#. Работа с файловой системой. Библиотека Оokii Dialogs WPF
MVVM - просто о сложном. Пример на C#
MVVM и внедрение зависимостей Часть 1
MVVM и внедрение зависимостей. Часть 2
Теги: #mvvm, #c#, #программирование
Ваш комментарий успешно добавлен.
После проверки комментарий будет опубликован на сайте.