Статьи

Как использовать MVVM в универсальном приложении для Windows

Шаблон Model-View-ViewModel (MVVM) помогает разработчикам отделить бизнес-логику приложения и логику представления от его пользовательского интерфейса. Поддержание четкого разделения между логикой приложения и пользовательским интерфейсом помогает решать проблемы разработки и проектирования, упрощая тестирование, обслуживание и разработку приложения. Это также может улучшить возможность многократного использования кода и позволяет нескольким разработчикам легче сотрудничать при работе над одним проектом.

Используя шаблон MVVM, пользовательский интерфейс приложения и базовая презентация и бизнес-логика разделены на три компонента:

  • Компонент представления инкапсулирует пользовательский интерфейс и логику пользовательского интерфейса.
  • Компонент модели представления инкапсулирует логику представления и состояние.
  • Уровень модели инкапсулирует бизнес-логику и данные приложения.

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

Из этого туториала Вы узнаете, как создать универсальное приложение для Windows с поддержкой MVVM Light. Вы узнаете, как:

  • создать универсальное приложение для Windows и добавить поддержку MVVM Light
  • реализовать структуру каталогов
  • добавить слой модели представления
  • связать контекст данных
  • реализовать службу обмена сообщениями для передачи сообщений между моделями представления

Начнем с создания универсального приложения для Windows. Выберите « Новый проект» в меню « Файл» в Visual Studio. Разверните Шаблоны > Visual C # > Windows > Windows 8 > Universal и выберите Пустое приложение (Universal Windows 8.1) из списка шаблонов проектов. Назовите свой проект и нажмите OK, чтобы создать проект.

Создание универсального приложения для Windows

Это создает два новых приложения (Windows Phone 8.1 и Windows 8.1) и один общий проект. Проекты Windows Phone 8.1 и Windows 8.1 являются проектами, специфичными для платформы, и отвечают за создание пакетов приложений (.appx) для соответствующих платформ. Общий проект — это контейнер для кода, который выполняется на обеих платформах.

Щелкните правой кнопкой мыши имя решения в обозревателе решений и выберите « Управление пакетами Nuget для решения» .

Выберите Управление пакетами Nuget для решения

Выберите вкладку « Обзор » и выполните поиск MVVM Light . Выберите пакет MvvmLightLibs из результатов поиска. Проверьте проекты Windows 8.1 и Windows Phone 8.1 и нажмите « Установить», чтобы добавить библиотеки MVVM Light в приложения.

Поиск и установка MvvmLightLibs

К этому моменту вы добавили поддержку MVVM Light для обоих ваших приложений.

Универсальное приложение Windows, которое принимает шаблон MVVM, требует определенной структуры каталогов. На следующем снимке показана возможная структура файла проекта для универсального приложения Windows.

Структура файла проекта

Позвольте мне познакомить вас со структурой проекта типичного приложения Univesal для Windows, в котором используется шаблон MVVM:

  • Элементы управления . Этот каталог содержит повторно используемые элементы управления пользовательского интерфейса (независимые от приложений представления). Элементы управления для конкретной платформы добавляются непосредственно в проект для конкретной платформы.
  • Строки : этот каталог содержит строки и ресурсы для локализации приложения. Каталог Strings содержит отдельные каталоги для каждого поддерживаемого языка. Например, каталог en-US содержит ресурсы для английского (США) языка.
  • Модели . В шаблоне MVVM модель инкапсулирует бизнес-логику и данные. Как правило, модель реализует средства, облегчающие привязку свойств к слою вида. Это означает, что он поддерживает уведомления «свойство изменено» и «коллекция изменено» через интерфейсы INotifyCollectionChanged и INotifyCollectionChanged .
  • ViewModels : модель представления в шаблоне MVVM инкапсулирует логику представления и данные для представления. Он не имеет прямой ссылки на представление или каких-либо знаний о реализации или типе представления.
  • Конвертеры : этот каталог содержит конвертеры значений. Преобразователь значений — это удобный способ преобразования данных из одного типа в другой. Он реализует интерфейс IValueConverter .
  • Темы : Каталог тем содержит ресурсы темы, имеющие тип ResourceDictionary . Специальные ресурсы платформы добавляются непосредственно в конкретный проект, а общие ресурсы добавляются в общий проект.
  • Сервисы : этот раздел может включать в себя классы для вызовов веб-сервисов, сервис навигации и т.д.
  • Utils включает в себя служебные функции, которые можно использовать в приложении. Примеры включают AppCache , FileUtils , Constants , NetworkAvailability , GeoLocation и т. Д.
  • Представления : этот каталог содержит макеты пользовательского интерфейса. Специфические представления платформы добавляются непосредственно в конкретный проект платформы, а общие представления добавляются в общий проект.

В зависимости от типа представления имя должно заканчиваться:

  • Окно , немодальное окно
  • Диалог , (модальное) диалоговое окно
  • Страница , просмотр страницы (в основном используется в приложениях Windows Phone и Windows Store)
  • Представление , представление, которое используется как подпредставление в другом представлении, странице, окне или диалоге

Название модели представления состоит из имени соответствующего представления и слова «Модель». Модели представлений хранятся в том же месте в каталоге ViewModels, что и их соответствующие представления в каталоге представлений.

Уровень модели представления реализует свойства и команды, с которыми представление может связывать данные и уведомлять представление о любых изменениях состояния посредством событий уведомления об изменениях. Свойства и команды, предоставляемые моделью представления, определяют функциональные возможности, предлагаемые пользовательским интерфейсом. В следующем списке приведены характеристики, задачи и обязанности уровня модели представления:

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

На следующих шагах мы добавляем два файла в слой модели представления, ViewModelLocator.cs и MainViewModel.cs .

Сначала щелкните правой кнопкой мыши общий проект и выберите « Добавить» , « Новая папка» . Назовите папку ViewModels . Затем щелкните правой кнопкой мыши папку ViewModels и выберите Add , New Item, чтобы добавить класс MainViewModel .

Измените класс MainViewModel чтобы он выглядел так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MainViewModel : ViewModelBase
{
    private string _helloWorld;
 
    public string HelloWorld
    {
        get
        {
            return _helloWorld;
        }
        set
        {
            Set(() => HelloWorld, ref _helloWorld, value);
        }
    }
 
    public MainViewModel()
    {
        HelloWorld = IsInDesignMode
            ?
            : «Runs in runtime mode»;
    }
}

Класс содержит открытое свойство HelloWorld типа string . Вы можете добавить дополнительные методы, наблюдаемые свойства и команды в модель представления.

Мы добавим открытое свойство для всех моделей представлений в классе ViewModelLocator и создадим новый ресурс, который мы будем использовать в конструкторе.

Щелкните правой кнопкой мыши папку ViewModels и выберите « Добавить» , « Новый элемент» . Выберите класс и назовите его ViewModelLocator.cs . Обновите класс ViewModelLocator как показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class ViewModelLocator
{
    public MainViewModel Main
    {
        get
        {
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }
 
    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<MainViewModel>();
    }
}

Класс ViewModelLocator содержит открытое свойство Main , метод MainViewModel которого возвращает экземпляр класса MainViewModel . Конструктор ViewModelLocator регистрирует экземпляр SimpleIoc сервисе SimpleIoc .

Затем откройте файл App.xaml и добавьте новый ресурс с ViewModelLocator для использования в конструкторе.

1
2
3
<Application.Resources>
    <viewModels:ViewModelLocator x:Key=»Locator» />
</Application.Resources>

Представление и модель представления могут быть построены и связаны во время выполнения несколькими способами. Самый простой подход — для представления создать экземпляр соответствующей модели представления в XAML. Вы также можете указать в XAML, что модель представления установлена ​​как контекст данных представления.

1
2
3
<Page.DataContext>
    <vm:MainViewModel/>
</Page.DataContext>

Когда страница MainPage.xaml инициализируется, экземпляр MainViewModel автоматически MainViewModel и устанавливается как контекст данных представления. Обратите внимание, что модель представления должна иметь конструктор по умолчанию без параметров, чтобы этот подход работал.

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

1
2
3
4
5
public MainPage()
{
    InitializeComponent();
    this.DataContext = new MainViewModel();
}

Другой подход заключается в создании экземпляра модели представления и связывании его с его представлением с использованием локатора модели представления. В примере приложения мы используем класс ViewModelLocator для разрешения модели представления для MainPage.xaml .

1
2
3
<Page.DataContext>
    <Binding Path=»Main» Source=»{StaticResource Locator}» />
</Page.DataContext>

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

1
<TextBlock Text=»{Binding HelloWorld}» FontSize=»20″ HorizontalAlignment=»Center» VerticalAlignment=»Center»/>

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

Модель представления, которая получает данные поиска, просто отправит «поисковое» сообщение, которое будет использовано любой моделью представления, которая в настоящее время зарегистрирована для использования сообщения. Преимущества использования службы обмена сообщениями:

  • простая связь между моделями представлений без необходимости знать друг о друге
  • больше потребителей сообщений может быть добавлено без особых усилий
  • это упрощает просмотр моделей

Отправить сообщение:

1
MessengerInstance.Send(payload, token);

Чтобы получить сообщение:

1
2
MessengerInstance.Register<PayloadType>(
   this, token, payload => SomeAction(payload));

В примере приложения мы отправим сообщение из MainViewModel , которое будет получено MainPage.xaml . Это шаги, необходимые для использования службы сообщений.

Создайте новый класс в проекте и назовите его ShowMessageDialog .

1
2
3
4
public class ShowMessageDialog
{
   public string Message { get;
}

В MainViewModel.cs создайте экземпляр ShowMessageDialog и используйте объект Messenger для передачи сообщения.

1
2
3
4
5
6
private object ShowMessage()
{
    var msg = new ShowMessageDialog { Message = «Hello World» };
    Messenger.Default.Send<ShowMessageDialog>(msg);
    return null;
}

Это передает сообщение. Нам остается только зарегистрировать получателя и ответить на сообщение.

Откройте MainPage.xaml.cs и зарегистрируйтесь для сообщения в конструкторе.

1
2
3
4
5
6
7
8
9
public MainPage()
{
    this.InitializeComponent();
    Messenger.Default.Register<ShowMessageDialog>
    (
         this,
         (action) => ReceiveMessage(action)
    );
}

ReceiveMessage — это метод, который вам нужно реализовать. Он возьмет объект Message и использует DialogService для отображения диалогового окна.

1
2
3
4
5
private async void ReceiveMessage(ShowMessageDialog action)
{
    DialogService dialogService= new DialogService();
    await dialogService.ShowMessage(action.Message, «Sample Universal App»);
}

Теперь, когда мы можем отправлять и получать сообщения, нам нужно вызвать метод ShowMessage . MVVM Light обеспечивает поддержку RelayCommand , которую можно использовать для создания команд в модели представления. Добавьте открытое свойство ShowMessageCommand в классе MainViewModel которое вызывает метод ShowMessage .

1
2
private RelayCommand _showMessageCommand;
public RelayCommand ShowMessageCommand => _showMessageCommand ??

Затем добавьте Button в MainPage.xaml и привяжите ShowMessageCommand к его свойству Command .

1
<Button Command=»{Binding ShowMessageCommand}» Content=»Click Me» HorizontalAlignment=»Center»/>

Разверните приложение, чтобы увидеть, все ли работает как положено. Вот снимок того, как MainPage.xaml выглядит в Windows 8.1.

MainPagexaml UI

Когда вы нажимаете кнопку Click Me , появляется диалоговое окно.

Всплывающее диалоговое окно на MainPagexaml

Messenger — это мощный компонент, который может упростить общение, но также затрудняет отладку кода, поскольку на первый взгляд не всегда ясно, какие объекты получают сообщение.

Благодаря реализации шаблона MVVM у нас есть четкое разделение между видом, моделью вида и слоями модели. Как правило, мы пытаемся разработать модель представления так, чтобы она ничего не знала о представлении, которое оно управляет. Это имеет несколько преимуществ:

  • Команда разработчиков может работать независимо от команды интерфейса пользователя.
  • Модель представления можно легко протестировать, просто вызвав некоторые команды и методы и подтвердив значение свойств.
  • В представление можно вносить изменения, не беспокоясь о том, какое влияние это окажет на модель представления и модель.

Не стесняйтесь загружать исходные файлы учебника для использования в качестве справочного материала.