Подтвердить что ты не робот

Почему избежать кода в шаблоне MVVM WPF?

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

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

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

EDIT: мой вопрос заключается в следующем: почему подход, подобный AttachedCommandBehavior или InvokeCommandAction, пытается избежать кодирования кода.

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

Что касается вопроса (1), я бы подумал о следующей ситуации, как из AttachedCommandBehavior. Поскольку Border не реализует 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, как указано выше, неплохо просто потому, что разница между ними заключается только в том, где привязка команды или добавления обработчика событий.

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

4b9b3361

Ответ 1

почему пустая кодировка рассматривается как хорошо спроектированная MVVM

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

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

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

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

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

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

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


Edit:

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

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

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

а роль представления отображает некоторое содержимое и синхронизирует viewmodel (имеющий код привязки данных)

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

Ответ 2

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

  • Я никогда не видел дизайнера, который использует Blend или понимает XAML.
  • Почти все XAML написаны самим кодером.

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

Просто мои мысли!