Basic concepts of MVVM— what should a ViewModel do?

84

Trying to grasp the concepts of MVVM, I have already read several blogs and looked at a few projects.

From what I understand, a View is dumb, it just knows how to present something that is passed to it.

Модели - это просто простые данные, а ViewModel - это нечто, что действует как отступ между ними, что он должен получать информацию от модели и передавать ее в представление , а представление должно знать, как ее представить. Или наоборот, если информация в представлении изменится, она должна передать это изменение модели .

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

РКМ
источник
2
Не могу согласиться с утверждением, что точка зрения «просто знаю, как представить то, что ей передается». View берет данные с ВМ. Никто не передает ему данные. Никто не знает о взгляде. Это важное отличие от MVP. В MVP (вы можете думать об этом как о простом приложении WPF с логикой выделенного кода, это шаблон MVP) выделенный код - это ведущий, который передает данные в представление, как вы сказали.
Григорий

Ответы:

149

Мне нравится думать об этом так:

Взгляды, как вы говорите, глупы. Джош Смит, автор основополагающей статьи MSDN о MVVM, на которую часто ссылаются, сказал, что представления - это «одежда, которую носят данные». Представления никогда не содержат данных и не управляют ими напрямую, они просто привязаны к свойствам и командам ваших моделей представления.

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

Это подводит нас к моделям просмотра. Кто они такие? Это объекты, моделирующие приложение с графическим интерфейсом., что означает, что они предоставляют данные и функции, которые будут использоваться представлениями. Именно они определяют структуру и поведение реального приложения, которое вы создаете. Для объектов модели домен - это любой домен, который вы выбираете (музыкальный магазин, браузер организационной диаграммы и т. Д.), Но для модели просмотра домен представляет собой графическое приложение. Ваши модели просмотра будут инкапсулировать поведение и данные всего, что делает ваше приложение. Они собираются предоставлять объекты и списки как свойства, а также такие вещи, как команды. Команда - это просто поведение (в простейшем случае, вызов метода), заключенное в объект, который ее переносит - эта идея важна, потому что представления управляются привязкой данных, которая прикрепляет визуальные элементы управления к объектам. В MVVM вы не даете кнопке метод обработчика Click,

Для меня наиболее запутанными были следующие моменты:

  • Несмотря на то, что модели представления являются моделями графического приложения, они напрямую не ссылаются на визуальные концепции и не используют их. Например, вам не нужны ссылки на элементы управления Windows в ваших ViewModels - эти вещи находятся в представлении. ViewModels просто предоставляют данные и поведение элементам управления или другим объектам, которые будут с ними связываться. Например, у вас есть представление со списком в нем? В вашей модели просмотра почти наверняка будет какая-то коллекция. Есть ли у вашего представления кнопки? В вашей модели просмотра почти наверняка будут присутствовать некоторые команды.
  • Есть несколько видов объектов, которые можно рассматривать как "модели просмотра". Самый простой для понимания вид модели представления - это модель, которая непосредственно представляет элемент управления или экран в соотношении 1: 1, например, «экран XYZ имеет текстовое поле, поле списка и три кнопки, поэтому модели представления нужна строка, коллекция, и три команды ". Другой тип объекта, который вписывается в слой модели представления, - это оболочка вокруг объекта модели, которая придает ему поведение и делает его более пригодным для использования в представлении - здесь вы познакомитесь с концепциями «толстого» и «тонкого» слоев модели представления. «Тонкий» слой модели представления - это набор моделей представления, которые предоставляют объекты вашей модели непосредственно представлениям, то есть представления в конечном итоге привязываются непосредственно к свойствам объектов модели. Это может работать для таких вещей, как простые представления только для чтения, но что, если вы хотите, чтобы поведение было связано с каждым объектом? Вы не хотите, чтобы это было в модели, потому что модель не связана с приложением, она связана только с вашим доменом. Вы можете поместить его в объект, который обертывает ваш объект модели и предлагает более удобные для привязки данные и варианты поведения. Этот объект-оболочка также считается моделью представления, и их наличие приводит к «более толстому» слою модели представления, где ваши представления никогда не привязываются напрямую к чему-либо в классе модели. Коллекции будут содержать модели представления, которые обертывают модели, а не просто сами модели. Вы можете поместить его в объект, который обертывает ваш объект модели и предлагает более удобные для привязки данные и варианты поведения. Этот объект-оболочка также считается моделью представления, и их наличие приводит к «более толстому» слою модели представления, где ваши представления никогда не привязываются напрямую к чему-либо в классе модели. Коллекции будут содержать модели представления, которые обертывают модели, а не просто сами модели. Вы можете поместить его в объект, который обертывает ваш объект модели и предлагает более удобные для привязки данные и варианты поведения. Этот объект-оболочка также считается моделью представления, и их наличие приводит к «более толстому» слою модели представления, где ваши представления никогда не привязываются напрямую к чему-либо в классе модели. Коллекции будут содержать модели представления, которые обертывают модели, а не просто сами модели.

Кроличья нора идет глубже - есть много идиом, которые нужно выяснить, например, ValueConverters, которые поддерживают работу MVVM, и есть много чего применить, когда вы начинаете думать о таких вещах, как смешиваемость, тестирование и то, как передавать данные в вашем приложении и гарантировать, что каждая модель представления имеет доступ к нужному поведению (здесь и вступает в силу внедрение зависимостей), но, надеюсь, приведенное выше - хорошее начало. Ключ в том, чтобы думать о ваших визуальных эффектах, вашем домене, структуре и поведении вашего реального приложения как о трех разных вещах.

законник
источник
3
+1 - Я оказался здесь, потому что меня смутила "оболочка" ViewModel, встречающаяся в некоторых примерах кода. Спасибо за
разъяснение
1
Отличный ответ - если бы я мог +10.
Ник Ходжес
1
@nlawalker Очень круто! Вышеприведенный двойной комментарий очень долго сбивал меня с толку. Во многих статьях и блогах рассказывается только о "ключевых особенностях" MVVM, но когда вы пытаетесь разобраться с этим, все становится очень сложным ! Например, "Как перемещаться по этим представлениям?" «Какова подходящая степень детализации при разработке ViewModels?» «Должен ли View иметь соответствующую ViewModel или одна ViewModel может быть повторно использована в разных View?» Ваше разъяснение о ViewModel, составленном из «Slim VM» и «Thick VM» действительно имеет смысл! Я пробую, это работает хорошо, поэтому далеко! :)
Claw
@nlawalker Спасибо! И еще вопрос: у меня есть treeView и я делаю TreeViewViewModel. Итак, если я создам такие методы, как ExpandTree () в моей ViewModel. Это правильный путь?
user2545071
Вау, это отличная статья, довольно хорошая работа @nlawalker
Вивек Шукла
26

Используя эту невероятно полезную статью в качестве источника, вот краткое изложение View , ViewModel и Model .


Посмотреть:

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

  • Представление ссылается на модель представления через свое DataContextсвойство. Элементы управления в представлении - это данные, привязанные к свойствам и командам, предоставляемым моделью представления.

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

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

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

ПРИМЕЧАНИЕ.
Поскольку модель представления не должна иметь явных сведений о конкретных визуальных элементах в представлении, код для программного управления визуальными элементами внутри представления должен находиться в выделенном коде представления или быть инкапсулирован в поведение.


Просмотреть модель:

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

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

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

  • Модель представления может определять логические состояния, которые представление может визуально представлять пользователю.

ПРИМЕЧАНИЕ.
Все, что важно для логического поведения приложения, должно входить в модель представления. Код для извлечения или управления элементами данных, которые должны отображаться в представлении посредством привязки данных, должен находиться в модели представления.


Модель:

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

  • Классы модели не ссылаются напрямую на классы представления или модели представления и не зависят от того, как они реализованы.

  • Классы модели обычно предоставляют событие свойства и изменение сбора уведомлений через те INotifyPropertyChangedи INotifyCollectionChangedинтерфейсы. Это позволяет им легко привязывать данные в представлении. Классы модели, представляющие коллекции объектов, обычно являются производными от ObservableCollection<T>класса.

  • Классы модели обычно обеспечивают проверку данных и сообщения об ошибках через интерфейсы IDataErrorInfoили INotifyDataErrorInfo.

  • Классы модели обычно используются вместе со службой или репозиторием, которые инкапсулируют доступ к данным и кэширование.

Дом
источник
18

Я написал это примерно на "простом английском" из этой серии статей о MVVM . В частности, эта диаграмма , вероятно, является самым простым и кратким объяснением.

При этом, по сути, «модель» - это ваши данные или бизнес-правила. Он действительно не должен знать о том, как и где он будет использоваться, и особенно о том, какая технология будет его использовать. «Модель» - это ядро ​​приложения, и ему не нужно беспокоиться о том, является ли приложение WPF, Silverlight, Windows Forms, ASP.NET и т. Д. - это просто «само» в чистом виде.

«Просмотр» - это часть, которая полностью зависит от технологии. В MVVM в идеале представление должно быть почти на 100% XAML, так как это дает огромные преимущества для гибкости.

Однако должно быть что-то, что переводит информацию из модели в некоторую форму, в которой ее можно использовать с помощью имеющейся технологии - здесь в игру вступает ViewModel. Например, это часто «обертывает» классы модели в «ViewModel» для этих конкретных данных, которые включают команды (для выполнения логики), инструменты INotifyPropertyChanged(для поддержки привязки данных) и т. Д. Вот и все - это мост, который делает модель может использоваться View.

Рид Копси
источник
Хорошо спасибо. Я думал о Модели как об объектах, а ViewModel как о методах обработки объектов, так что представление может понимать «объекты» Модели. Но мне сказали, что это неправильно, что сама ViewModel тоже является объектами. Думаю, вот что меня действительно смущает.
RKM
@Rosie: Я бы порекомендовал прочитать (или хотя бы бегло просмотреть) мою цитируемую серию. Я написал это специально, потому что есть несколько (почти нет) статей о MVVM, которые еще не предполагают, что вы понимаете MVC или MVP и т. Д. Это действительно «пошаговый» переход;)
Рид Копси
Понимая, что это немного зомби-потоки ... На вашей диаграмме сказано, что виртуальная машина содержит "состояние и логику, зависящие от приложения " (мой emph). Означает ли это, что, по вашему мнению, виртуальная машина может / должна содержать логику контроля качества данных? Связанный с ним RssWpfMVVM.csproj, похоже, не имеет очевидного QA в своих двух моделях просмотра.
ruffin
1

Отличное введение в MVVM можно найти в видео Джейсона Долинджера здесь . Я довольно долго держал видео при себе, когда только начинал, оно действительно полезно.

Филипе Мигель
источник
1
Ссылка мертва
ибрахим махрир
1
@ibrahimmahrir ~ Я обновил ссылку на рабочий URL. Сейчас скачиваю видео.
InteXX
0

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

Sprotty
источник