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

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

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

Реализация шаблона Model-View-ViewModel (MVVM) в проектах Uno Platform аналогична любой другой цепочке инструментов на основе XAML Page, например WPF и Xamarin.Forms. Вы раскрываете всю мощь MVVM, когда реализуете решение Dependency Injection, поскольку оно упрощает все ваши зависимости ViewModel. У Microsoft есть отличная библиотека сообщества для внедрения зависимостей под названием  Microsoft.Extensions.DependencyInjection.

В этой статье мы рассмотрим, как настроить  Microsoft.Extensions.DependencyInjection для работы с платформой Uno в архитектуре MVVM. Это будет базовое введение, которое поможет вам начать работу, и есть много улучшений, которые вы можете добавить позже или использовать сторонние библиотеки, чтобы упростить это.

Архитектура

Прежде чем мы начнем рассматривать какой-либо код, давайте поймем, почему мы хотим использовать Dependency Injection и Model-View-ViewModel (MVVM) , поскольку это два очень разных шаблона, которые часто используются вместе для решения разных задач.

  • Внедрение зависимости
  • Модель-представление-ViewModel (MVVM)

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

Внедрение зависимостей — это тип инверсии управления из принципов SOLID объектно-ориентированного программирования. Это позволяет вашей системе автоматически внедрять экземпляры объектов в конструктор класса, пока она не знает об экземплярах объектов. 

  • S - принцип единой ответственности
  • O - открытый закрытый принцип
  • L - принцип замены Лисков
  • I - Принципы разделения интерфейсов
  • D - Принцип инверсии зависимостей

Если вы не знакомы с принципами SOLID, я привожу краткие описания и несколько примеров, чтобы помочь. Внедрение зависимостей — это реализация  принципа инверсии зависимостей.

Принцип единой ответственности

Принцип единой ответственности гласит, что ваш класс должен иметь только одну работу и не иметь других обязанностей. Это означает, что многие из ваших классов должны быть разбиты на более мелкие классы, чтобы управлять вашими бизнес-правилами и операциями по мере роста вашего проекта.

Открытый закрытый принцип

Принцип Open Closed гласит, что класс должен быть открыт для расширения, но закрыт для модификации. Примером этого в AC# может быть создание возможности переопределения метода в дочернем классе, где родительский класс помечает этот метод как виртуальный.

Родительский класс

 

1
2
3
4
5
6
7
public class Parent
{
    public virtual void Hello()
    {
        Console.WriteLine("Hello From the Parent");
    }
}
 

Дочерний класс

 

1
2
3
4
5
6
7
public class Child : Parent
{
    public override void Hello()
    {
        Console.WriteLine("Hello from the child");
    }
}
 

Принцип замены Лисков

Принцип подстановки Лисков гласит, что объекты могут быть заменены экземплярами их подтипов без необходимости повторной компиляции приложения. Продолжая наш пример выше с  Child  и  Parent в принципе Open Closed, я мог бы использовать Child , взаимозаменяемый с Parent. Если у меня есть метод, который использует параметр  Parent , этот метод также может принимать  Child и работать так же.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Program
{
    public static void Main(string args[])
    {
        var child = new Child();
        var parent = new Parent();
 
        MyMethod(child);
        MyMethod(parent);
    }
 
    public static void MyMethod(Parent p)
    {
        p.Hello();
    }
}
 

Принцип разделения интерфейса

Принцип разделения интерфейса гласит, что ни один клиент не должен зависеть от методов, которые он не использует. Это означает, что лучше иметь много небольших интерфейсов, которые обрабатывают каждый конкретный вариант использования, создавая контракт для вашего класса. Нарушением этого принципа считается наличие универсальных интерфейсов, которые используются в широком спектре объектов. Этот тип реализации делает вашу кодовую базу хрупкой и трудной для изменения. Интерфейсы должны облегчать вам изменение вашей кодовой базы.

Принцип инверсии зависимости

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

Это фундаментальный принцип внедрения зависимостей.

Представление модели ViewModel (MVVM)

 Архитектура Mode View ViewModel — это популярный шаблон системного проектирования, который используется во многих приложениях на основе пользовательского интерфейса. В стеке Microsoft он обычно находится в:

  • Платформа представления Windows (WPF)
  • Универсальная платформа Windows (UWP)
  • Xamarin.Формы
  • Платформа Уно
  • и т.п.

Цель архитектуры MVVM — отделить ваши бизнес-правила от представления или страницы. Это обеспечивает чистую реализацию шаблона единой ответственности и позволяет разработчикам разместить всю логику пользовательского интерфейса в одном месте, а все бизнес-правила — в другом.

Вид

Код пользовательского интерфейса, а в случае платформы Uno это будет ваша XAML-страница и код. Если ваша страница называется  MainPage , у вас будет 2 файла, представляющих ваш вид .

  • MainPage.xaml
  • Главная страница.xaml.cs

В этих файлах вы никогда не должны вызывать запрос к базе данных, вызывать серверные службы или другие API-интерфейсы, связанные с бизнесом. Ваше представление контролирует только то, как вещи отображаются на экране. Чуть позже мы поговорим о привязке данных, которая связывает View с ViewModel.

ViewModel

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

По моему опыту, ViewModel лучше всего использовать в качестве оркестратора, я стараюсь не позволять своим ViewModels напрямую обращаться к базе данных или службе. Я создаю другие службы и классы для обработки этих правил и позволяю своей ViewModel управлять этими вызовами. ViewModel очень легко стать неуправляемой из-за слишком большого количества зависимостей и нарушения принципа единой ответственности, описанного выше.

Модель 

Модель — это простой класс, который содержит свойства и обычно не содержит никаких бизнес-правил. Этот класс используется для преобразования любых сложных типов из объекта базы данных для сервисного уровня в простой в использовании класс для уровня представления вашего приложения. ViewModel может ссылаться на модель, чтобы легко отображать данные в представлении.

Привязка данных

Приложения MVVM используют концепцию привязки данных для подключения представления к модели представления. Это позволяет коду View привязываться непосредственно к свойству в ViewModel и отображать его на экране, не зная, как был заполнен этот объект. Существует несколько различных методов привязки данных . Давайте рассмотрим самый простой пример.

Давайте создадим простую связь View/ViewModel, в которой мы отображаем сообщение в TextBlock.

ViewModel

 

1
2
3
4
public class MyViewModel
{
    public string Message { get => "Hello from the ViewModel!"; }
}
 

Вид  

 

1
<TextBlock Text="{Binding Message}" />
 

В код представления мы добавляем специальный синтаксис, называемый расширением разметки, в качестве значения свойства для Text . Фигурные скобки сообщают системе, что мы собираемся использовать расширение разметки, а ключевое слово Binding сообщает системе, что нужно искать свойство DataContext  для  сообщения.

Заключение по архитектуре

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

Теперь мы можем начать работу с работающим приложением Uno Platform, чтобы узнать, как правильно настроить MVVM и внедрение зависимостей.

Новый проект

Давайте начнем с создания нового проекта Uno Platform, если вы еще не загрузили расширения Visual Studio, я настоятельно рекомендую это сделать!

Откройте Visual Studio и перейдите в  File-> New  и найдите платформу uno. Вы хотите выбрать кросс-платформенное приложение (платформа Uno) . Следуйте инструкциям, и он создаст вам новый проект. Я назвал свой проект:  Sample.MvvmAndDependencyInjection .

 

MVVM

Давайте начнем с настройки нашего проекта, чтобы он мог поддерживать архитектуру MVVM. 

  1. Найти общий код
  2. Создайте папки для моделей, представлений и моделей представления.
  3. Переместить классы в новые папки
  4. Обновленная последовательность запуска

Найти общий код

Общий код в проектах Uno Platform легко найти, обычно в нем есть общее ключевое слово. В моем примере мое имя проекта общего кода —  Sample.MvvmAndDependencyInjection.Shared. Ваш общий проект может иметь другое имя.

Создать новые папки

На верхнем уровне в общем проекте создайте следующие новые папки

  • Модели
  • Просмотры
  • ViewModels

 

Переместить классы

Для начала нам нужно переместить главную страницу в папку Views. После того, как вы переместили класс, вам нужно будет обновить пространство имен, будет 2 места, в которых необходимо обновить пространство имен: MainPage.xaml и  MainPage.xaml.cs . Поскольку большинство страниц на платформе Uno используют концепцию частичных классов, необходимо обновить оба спота, потому что вместе они составляют 1 объект  MainPage .

MainPage.xaml

 

1
2
3
4
5
6
7
8
9
10
11
12
<Page
    x:Class="Sample.MvvmAndDependencyInjection.MainPage.Views"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Hello, world!" Margin="20" FontSize="30" />
    </Grid>
</Page>
 

Обновите свойство x:Class , чтобы включить .Views в конце.

Главная страница.xaml.cs

 

1
2
3
4
5
6
7
8
9
10
namespace Sample.MvvmAndDependencyInjection.Views
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
    }
}
 

Легче найти в коде C#, обновите пространство имен, чтобы включить .Views в конце.

Обновить последовательность запуска

Теперь, когда главная страница перемещена, вам нужно будет обновить последовательность запуска в  App.xaml.cs , чтобы указать новое расположение наших представлений. В верхней части файла добавьте новый оператор using, который ссылается на ваше пространство имен Views.

 

1
using Sample.MvvmAndDependencyInjection.Views;
 

Добавить MainViewModel 

На этом этапе ваше приложение должно собраться и развернуться без проблем. Все настроено, и вы готовы приступить к созданию ViewModels. Давайте добавим  MainViewModel , которая обновляет сообщение на MainPage . Это будет сделано в 3 шага

  1. Создайте ViewModel и свойство сообщения
  2. Создание экземпляра DataContext в коде позади
  3. Добавить привязку данных в представлении

MainViewModel

MainViewModel будет простым классом, который просто хранит сообщение как общедоступное свойство.

 

1
2
3
4
public class MainViewModel
{
    public string Message { get => "Hello from our MainViewModel"; }
}
 

Создать экземпляр DataContext

Все страницы имеют свойство, называемое  DataContext , это свойство, которое соединяет ваше представление с вашей моделью представления. Без него View не понял бы, где взять свойства, которые мы планируем привязать. 

В конструкторе просто создайте экземпляр нашей ViewModel и установите его равным DataContext

 

1
2
3
4
5
6
7
8
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}
 

Добавить привязку данных в представлении

Теперь, когда DataContext  установлен и у нас есть  MainViewModel , представление может добавить синтаксис привязки данных для установки свойства Text в TextBlock.

 

1
2
3
4
5
6
7
8
9
10
11
12
<Page
    x:Class="Sample.MvvmAndDependencyInjection.MainPage.Views"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding Message}" Margin="20" FontSize="30" />
    </Grid>
</Page>
 

Заключение МВВМ

Это все, что нужно для базовой реализации MVVM в проекте Uno Platform! Это базовое введение в MVVM, и есть много других тем, полезных в проекте MVVM. Если вы хотите узнать больше о следующих шагах для MVVM, вот краткий список.

  • INotifyPropertyChanged — для обновлений привязки данных.
  • ViewModel Locator - автоматическое сопоставление ViewModel с представлением и устраняет необходимость вручную устанавливать DataContext

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

Теперь, когда у вас есть работающая базовая реализация MVVM, пора приступить к реализации внедрения зависимостей. Есть много библиотек и фреймворков, которые могут решить эту проблему, но мы будем использовать библиотеку сообщества, предоставленную Microsoft. Microsoft.Extensions.DependencyInjection становится стандартной библиотекой для многих открытых и закрытых исходных кодов в экосистеме .NET. Это отличная библиотека, в которой многие популярные функции внедрения зависимостей работают прямо из коробки.

Давайте начнем

  1. Добавить ссылку NuGet для Microsoft.Extensions.DependencyInjection
  2. Создать контейнер
  3. Создать службу сообщений
  4. Зарегистрируйте MessageService в контейнере
  5. Внедрить MessageService в MainViewModel

Добавить ссылки NuGet

Начните с добавления пакетов NuGet во все проекты. Щелкните правой кнопкой мыши уровень решения в обозревателе решений и выберите Управление NuGet. Как только у вас появится окно поиска, найдите  Microsoft.Extensions.DependencyInjection. 

 

Добавьте последнюю версию во все свои проекты.

Продолжение часть 2

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

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

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

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

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

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

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

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

Комментарии

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

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

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