Зачем избегать кода в шаблоне WPF MVVM?
В статье " Приложения 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 и его код, имеющий Border_MouseRightButtonDown
метод, который связан с (2) Джошом Симтом, указанным выше.
<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>
Я думаю, что использование codebehind, как указано выше, неплохо только потому, что разница между ними только в том случае, если есть привязка команды или обработчик события add.
Что Вы думаете об этом?
4 ответа
почему пустой код рассматривается как хорошо разработанный MVVM
Наличие файла с выделенным кодом, который состоит исключительно из вызова InitializeComponent() в его конструкторе, означает, что вы достигли чистоты - у вас абсолютно нулевая логика в вашем коде. Вы не загрязнили свое представление каким-либо кодом, который по праву принадлежит модели или модели. Это означает пару вещей:
- модель представления (и модель) легче тестировать изолированно
- Вы достигли хорошего уровня слабой связи, что дает отличные преимущества с точки зрения обслуживания и расширяемости
Преимущества действительно становятся заметными, когда вам приходится менять свой пользовательский интерфейс, то есть вы переходите от использования ListView к DataGrid или переходите от использования стандартных элементов управления Microsoft к использованию других поставщиков.
Как уже упоминалось, иногда невозможно избежать небольшого кода в файле code-behind. Вам следует убедиться, что код, который у вас есть, имеет чисто пользовательский интерфейс. Например, если у вас есть ComboA и ComboB, и ComboB установлен в ответ на выбор в ComboA, тогда установка SelectedIndex ComboB из представления - это хорошо, но установка Items или SelectedItem ComboB - нет - эти свойства оба связаны с данными и должны быть указаны через привязку к модели представления. Свойство SelectedIndex напрямую визуально связано и несколько не зависит от фактических данных (и не имеет отношения к модели представления).
Если вы обращаетесь к viewmodel из-за кода в представлении, вы должны попытаться сделать это через интерфейс. Это означает, что ваша модель представления внедряется или предоставляется представлению в качестве интерфейса. (Обратите внимание, что подсистема привязки не знает и не заботится об интерфейсе, она будет продолжать связываться в обычном режиме. В результате достигается лучший код с менее тесной связью). Как я кодирую, модель представления не имеет представления о существовании представления, а представление знает только о модели представления как о интерфейсе.
Однако следует помнить, что MVVM - это шаблон, а шаблон - просто рецепт или рецепт для достижения определенного результата в определенной ситуации. Это не должно восприниматься как религия, когда неверующие или неконформеры собираются отправиться в какое-то чистилище (хотя следование шаблону хорошо, если вы хотите избежать чистилища ада обслуживания и запаха кода).
Если вам нужен отличный пример того, как этот конкретный шаблон помогает, попробуйте написать несколько довольно сложных экранов в ASP.Net, а затем напишите то же самое в WPF или Silverlight и обратите внимание на разницу.
Редактировать:
позвольте мне ответить на некоторые ваши вопросы, надеюсь, это поможет....
Роль модели представления (модель представления), на мой взгляд, имеет логику пользовательского интерфейса и состояние представления.
У модели представления никогда не должно быть логики пользовательского интерфейса или "состояния просмотра". Для целей этого объяснения я бы определил состояние просмотра как положение прокрутки, индекс выбранной строки, выбранный индекс, размер окна и т. Д. Ни один из них не принадлежит модели представления; такие вещи, как SelectedIndex, зависят от способа отображения данных в пользовательском интерфейсе (если вы измените порядок сортировки DataGrid, SelectedIndex может измениться, даже если SelectedItem остается прежним). В этом конкретном случае SelectedItem может быть привязан к модели представления, но SelectedIndex не должен.
Если вам необходимо отслеживать информацию о типе сеанса пользовательского интерфейса, то вам следует придумать что-то общее (например, я сохранил состояние просмотра раньше, сохраняя важные данные в списке KeyValuePair), которое затем "сохраняется" с вызовом viewmodel (через интерфейс, о котором я упоминал ранее). Представление не имеет представления о том, как сохраняются данные, а модель представления не имеет представления о том, что данные поступают из представления (оно просто представило вызов через свой интерфейс).
и роль представления заключается в отображении некоторого содержимого и синхронизации модели представления (имеющей код привязки данных)
Да, обязанность представления - просто визуально отображать данные, представленные моделью представления. Модель представления получает данные из модели (модель отвечает за выполнение вызовов базы данных или вызовов веб-службы WCF, обычно это делается через "службу", но это совсем другое обсуждение). Затем модель представления может формировать или манипулировать данными, то есть может получать список всех клиентов, но только отображать отфильтрованную версию этого списка (может быть, текущих клиентов) в общедоступном свойстве, которое затем может связывать представление.
Если данные должны обрабатываться во что-то визуальное (типичным примером является значение перечисления, переводимое в цвет), тогда модель представления по-прежнему имеет только значения перечисления, и представление по-прежнему привязывается к этому значению, но представление также использует конвертер для перевода чистых данных в визуальное представление. Используя конвертер, модель представления по-прежнему избегает каких-либо действий, связанных с пользовательским интерфейсом, а представление избегает какой-либо реальной логики.
MVVM может полностью разделить код и дизайн страницы; кодеры заботятся только о кодировании, а дизайнеры - только о дизайне. Но:
- Я никогда не видел ни одного дизайнера, который бы использовал Blend или понимал XAML.
- Почти все XAML написаны самим кодером.
В коде нет ничего плохого по сути. Для простых случаев хорошо иметь это. Однако логикой пользовательского интерфейса может быть сложно управлять во многих сценариях. Инкапсуляция этой логики в подключенных моделях поведения и моделях представления позволяет нам изолировать переменные (и протестировать их), чтобы их было легче понять и поддерживать.
Если проблема заключается в тестируемости, то чем больше логики вашего пользовательского интерфейса вы можете инкапсулировать в моделях представления и прикрепленном поведении, тем больше вы сможете проверить, не прибегая к тестированию пользовательского интерфейса. (Хотя это не устраняет необходимость в тестировании пользовательского интерфейса в целом, оно обеспечивает первый уровень проверки перед началом тестирования пользовательского интерфейса, что потребует больше времени и ресурсов.
Я думаю, что цитируемый раздел относится к способу визуализации данных. Я думаю, что они означают, что вы не должны писать код в коде, который связан, например, с тем, как или где отображаются данные (например, что-то вроде: label1.Text = ...
). Выполнение подобных операций с использованием привязок облегчает разделение дизайна и кода (что произойдет, если вам нужно, чтобы данные отображались в текстовом поле с именем "tbTest" в более поздней версии? Вам придется изменить свой код позади).
Они не говорят, что у вас не должно быть кода в коде - они просто говорят, что в идеальном мире вы будете реагировать только на события или обрабатывать данные, которые иначе не могли бы быть обработаны.
По крайней мере, я так понимаю из приведенного вами раздела.
Шаблон MVVM мощный, но я считаю его слишком "пуристским". Я вижу преимущество в том, что код обрабатывает все команды и свойства в представлении, в то время как ViewModel занимается любым преобразованием в свойства бизнес-модели. Преимущество этого заключается в том, что если вы хотите изменить пользовательский интерфейс, возможно, с рабочего стола на браузер, скорее всего, это просто замена представления и его кода.
Только мои мысли!!