ПРОГРАММИРОВАНИЕ16 августа

MVVM и внедрение зависимостей. Часть 2

Начало 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 в контейнере

Теперь, когда мы определили наш 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

Теперь мы можем внедрить MessageService в MainViewModel и обновить свойство Message. Давайте разобьем это на 2 части:

  1. Внедрение конструктора
  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 

Перед созданием решения необходимо выполнить один последний шаг: необходимо правильно разрешить 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 является кроссплатформенной, этот код будет работать на разных платформах.

  • Андроид
  • iOS
  • ВАСМ 

Вывод

В этой статье рассматривается множество тем, посвященных созданию простого приложения MVVM, в котором используются передовые методы внедрения зависимостей. Если вы заблудились по пути или вам проще изучить пример кода, перейдите по ссылке на github ниже и загрузите весь код из этой статьи.

Источник

Ссылки на статьи

Делегат в Си Шарп

Диалог в WPF C#. Работа с файловой системой. Библиотека Оokii Dialogs WPF

Работа с файловой системой

Библиотека Оokii Dialogs WPF

MVVM - просто о сложном. Пример на C#

MVVM и внедрение зависимостей Часть 1

MVVM и внедрение зависимостей. Часть 2

 

Комментарии

Добавить комментарий:

Отметьте что вы не робот

Вернуться наверх