Зачем избегать кода в шаблоне WPF MVVM? - PullRequest
46 голосов
/ 21 июня 2011

В статье Приложения WPF с шаблоном проектирования Model-View-ViewModel автор Джош Смит сказал:

(1) В хорошо разработанномАрхитектура MVVM, код для большинства представлений должен быть пустым или, самое большее, содержать только код, который управляет элементами управления и ресурсами, содержащимися в этом представлении.(2) Иногда также необходимо написать код в коде представления, который взаимодействует с объектом ViewModel, например перехватить событие или вызвать метод, который в противном случае было бы очень трудно вызвать из самого ViewModel.

Мой вопрос в (1), почему пустой кодовый код рассматривается как хорошо спроектированный MVVM. (Звучит, что пустой кодовый код всегда хорош.)

РЕДАКТИРОВАТЬ: Мой вопрос, как следующий, почему такой подход, как AttachedCommandBehavior или InvokeCommandAction, пытаются избежать кодирования за кодом.

Позвольте мне объяснить более подробно.

Что касается (1), я бы подумал, что следующая ситуация с AttachedCommandBehavior .Поскольку Граница не реализует ICommandSource для MouseRightButtonDown, вы не можете обычно связывать событие и ICommand, но можете делать с AttachedCommandBehavior .

<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
    <local:CommandBehaviorCollection.Behaviors>
           <local:BehaviorBinding Event="MouseRightButtonDown" 
                  Command="{Binding SomeCommand}" 
                  CommandParameter="A Command on MouseRightButtonDown"/>
    </local:CommandBehaviorCollection.Behaviors>
</Border>

ИЛИ

Мы можем сделать это с System.Windows.Interactivity.InvokeCommandAction.

<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseRightButtonDown">
            <i:InvokeCommandAction Command="{Binding SomeCommand}" 
               CommandParameter="A Command on MouseRightButtonDown"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Border>

НО,

Мы используемследующий XAML и его codebehind, имеющий метод Border_MouseRightButtonDown, который связан с (2) Джошом Симтом, сказанным выше.только там, где есть привязка команды или обработчик события добавления.

Что вы думаете об этом?

Ответы [ 5 ]

63 голосов
/ 21 июня 2011

почему пустой код считается хорошо разработанным MVVM

Наличие файла с выделенным кодом, который состоит исключительно из вызова InitializeComponent () в его конструкторе, означает, что вы достигли чистоты - у вас абсолютно нулевая логика в вашем коде. Вы не загрязнили свое представление каким-либо кодом, который по праву принадлежит модели или модели. Это означает пару вещей:

  • модель представления (и модель) легче тестировать в изоляции
  • вы достигли хорошего уровня слабой связи, что дает отличные преимущества с точки зрения обслуживания и расширяемости

Преимущества действительно становятся заметными, когда вам приходится менять свой пользовательский интерфейс, т. Е. Переходить от использования ListView к DataGrid или переходить от использования стандартных элементов управления Microsoft к использованию других поставщиков.

Как уже упоминалось, иногда невозможно избежать небольшого кода в файле code-behind. Вам следует убедиться, что код, который у вас есть, имеет чисто пользовательский интерфейс. Например, если у вас есть ComboA и ComboB, и ComboB установлен в ответ на выбор в ComboA, тогда установка SelectedIndex ComboB из представления является хорошей, но установка Items или SelectedItem ComboB - нет - эти свойства оба связаны с данными и должны быть указаны через привязку к модели представления. Свойство SelectedIndex напрямую визуально связано и несколько не зависит от фактических данных (и не имеет отношения к модели представления).

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

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

Если вам нужен отличный пример того, как этот конкретный шаблон помогает, попробуйте написать несколько достаточно сложных экранов в ASP.Net, а затем напишите то же самое в WPF или Silverlight и обратите внимание на разницу.


Edit:

позвольте мне ответить на некоторые ваши вопросы, надеюсь, это поможет ....

Роль модели представления (модель представления), на мой взгляд, имеет логику пользовательского интерфейса и состояние представления.

У модели представления никогда не должно быть логики пользовательского интерфейса или "состояния просмотра". Для целей этого объяснения я бы определил состояние просмотра как положение прокрутки, индекс выбранной строки, выбранный индекс, размер окна и т. Д. Ни один из них не принадлежит модели представления; Такие вещи, как SelectedIndex, зависят от способа отображения данных в пользовательском интерфейсе (если вы измените порядок сортировки DataGrid, SelectedIndex может измениться, даже если SelectedItem остается прежним). В этом конкретном случае SelectedItem может быть привязан к модели представления, но SelectedIndex не должен.
Если вам нужно отслеживать информацию о типе сеанса пользовательского интерфейса, то вам следует придумать что-то общее (например, я сохранил состояние просмотра ранее, сохраняя важные данные в списке KeyValuePair), которое затем «сохраняется» с вызовом viewmodel (через интерфейс, о котором я упоминал ранее). Представление не имеет представления о том, как сохраняются данные, а модель представления не имеет представления о том, что данные поступают из представления (оно просто представило вызов через свой интерфейс).

и роль представления заключается в отображении некоторого содержимого и синхронизации модели представления (с кодом привязки данных)

Да, представление просто отвечает за визуальное отображение данных, представленных моделью представления.Модель представления получает данные из модели (модель отвечает за выполнение вызовов базы данных или вызовов веб-службы WCF, обычно это делается через «службу», но это совсем другое обсуждение).Затем модель представления может формировать или манипулировать данными, то есть она может получать список всех клиентов, но только отображать отфильтрованную версию этого списка (может быть, текущих клиентов) в общем свойстве, которое представление может затем связать.Если данные должны быть обработаны во что-то визуальное (общий пример - значение перечисления, переводимое в цвет), тогда модель представления все еще имеет только значения перечисления, и представление все еще привязывается к этому значению, но представление также использует конвертер для перевода чистых данных в визуальное представление.Используя конвертер, модель представления по-прежнему избегает каких-либо действий, связанных с пользовательским интерфейсом, а представление избегает какой-либо реальной логики.

8 голосов
/ 21 ноября 2014

MVVM может полностью разделить код и дизайн страницы; кодеры заботятся только о кодировании, а дизайнеры - только о дизайне. Но:

  1. Я никогда не видел ни одного дизайнера, который бы использовал Blend или понимал XAML.
  2. Почти все XAML написаны самим кодером.
5 голосов
/ 21 июня 2011

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

Если тестируемость важна, тем больше логики вашего пользовательского интерфейса вы можетеинкапсулируйте в viewmodels и прикрепленные поведения, тем больше вы сможете проверить, не прибегая к тестированию пользовательского интерфейса.(Хотя это не устраняет необходимость в тестировании пользовательского интерфейса в целом, оно обеспечивает первый уровень проверки перед началом тестирования пользовательского интерфейса, что потребует больше времени / ресурсов.

2 голосов
/ 21 июня 2011

Я думаю, что цитируемый раздел относится к способу визуализации данных.Я думаю, они означают, что вы не должны писать код в коде, который связан, например, с тем, как или где отображаются данные (например, что-то вроде: label1.Text = ...).Выполнение подобных операций с использованием привязок облегчает разделение дизайна и кода (что произойдет, если вам нужно, чтобы данные отображались в текстовом поле с именем «tbTest» в более поздней версии? Вам придется изменить свой код позади).

Они не говорят, что у вас не должно быть кода в коде - они просто говорят, что в идеальном мире вы будете реагировать только на события или обрабатывать данные, которые иначе не могли бы быть обработаны.

По крайней мере, я так понимаю из приведенного вами раздела.

0 голосов
/ 16 июля 2019

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

Только мои мысли !!

...