Кто должен контролировать навигацию в приложении MVVM?

Пример # 1: у меня есть представление, отображаемое в моем приложении MVVM (давайте использовать Silverlight для целей обсуждения), и я нажимаю кнопку, которая приведет меня к новой странице.

Пример # 2: в том же представлении есть еще одна кнопка, которая при нажатии должна открыть представление деталей в дочернем окне (диалог).

Мы знаем, что будут объекты Command, выставленные нашей ViewModel, привязанные к кнопкам с методами, которые отвечают на щелчок пользователя. Но что тогда? Как завершить действие? Даже если мы используем так называемый NavigationService, что мы говорим?

Чтобы быть более конкретным, в традиционной модели View-first (например, в схемах навигации на основе URL-адресов, например, в Интернете или в встроенной навигационной структуре SL) объекты Command должны были бы знать, какой вид отображать для следующего. Это, похоже, пересекает линию, когда дело доходит до разделения проблем, вызванных шаблоном.

С другой стороны, если кнопка не была подключена к объекту Command и ведет себя как гиперссылка, правила навигации могут быть определены в разметке. Но хотим ли мы, чтобы представления контролировали поток приложений и не являлись навигацией только другого типа бизнес-логики? (Я могу сказать «да» в некоторых случаях и нет в других.)

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

В соответствии с этой оценкой, какой-либо другой механизм во время выполнения должен «привязать» к тому, какой вид должен отображаться для каждой ViewModel. Но что, если мы хотим поделиться View с несколькими ViewModels или наоборот?

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

31 голос | спросил SonOfPirate 16 32011vEurope/Moscow11bEurope/MoscowWed, 16 Nov 2011 20:18:12 +0400 2011, 20:18:12

3 ответа


6

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

Первое решение состояло в том, чтобы использовать платформу Silverlight Page Navigation, предоставленную из коробки. Это решение было основано на нескольких факторах, включая знания о том, что этот тип навигации переносится Microsoft в приложения Windows 8 Metro и совместим с навигацией в приложениях Phone 7.

Чтобы он работал, я в дальнейшем рассмотрел работу, выполненную ASP.NET MVC с использованием навигации на основе условных обозначений. Элемент управления Frame использует URI для поиска отображаемой страницы. Сходство дало возможность использовать аналогичный подход на основе конвенций в приложении Silverlight. Хитрость заключалась в том, чтобы все это работало на MVVM-пути.

Решение - это NavigationService. Эта служба предоставляет несколько методов, таких как NavigateTo и Back, которые могут использовать ViewModels для инициирования изменения страницы. Когда запрашивается новая страница, NavigationService отправляет CurrentPageChangedMessage с помощью функции MVVMLight Messenger.

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

Возврат к NavigationService. Метод NavigateTo принимает имя целевой страницы. Чтобы убедиться, что в ViewModels нет проблем с пользовательским интерфейсом, используемое имя - это имя отображаемой модели ViewModel. Я фактически создал перечисление, которое имеет поле для каждого навигационного ViewModel в качестве помощника и для устранения магических строк по всему приложению. Функция сопоставления, упомянутая выше, разделит суффикс «ViewModel» от имени, добавит «Страница» к имени и задает полное имя «Views {Name} Page.xaml».

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

NavigationService.NavigateTo(ViewModels.CustomerDetails);

Значение CustomerDetails - это «CustomerDetailsViewModel», который сопоставляется с «Views \ CustomerDetailsPage.xaml».

Красота такого подхода заключается в том, что пользовательский интерфейс полностью отделен от ViewModels, но у нас есть полная поддержка навигации. Теперь я могу reskin мое приложение и всякий раз, когда я считаю нужным без каких-либо изменений кода.

Надеемся, что объяснение поможет.

ответил SonOfPirate 3 FebruaryEurope/MoscowbFri, 03 Feb 2012 06:53:39 +0400000000amFri, 03 Feb 2012 06:53:39 +040012 2012, 06:53:39
19

Навигацию всегда следует обрабатывать в ViewModel.

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

Я обычно имею ApplicationViewModel, или ShellViewModel, который обрабатывает общее состояние моего приложения. Это включает в себя CurrentPage (который является ViewModel) и код для обработки ChangePageEvents. (Он часто также используется для других объектов, таких как CurrentUser или ErrorMessages)

Итак, если какой-либо ViewModel в любом месте транслирует ChangePageEvent(new SomePageViewModel), ShellViewModel отобразит это сообщение и переключит CurrentPage на любую страницу, указанную в сообщении.

На самом деле я написал сообщение в блоге о навигации с MVVM , если вы 'заинтересовался

ответил Rachel 16 32011vEurope/Moscow11bEurope/MoscowWed, 16 Nov 2011 21:33:52 +0400 2011, 21:33:52
2

Подобно тому, что сказала Рейчел, мое приложение MVVM в основном имеет Presenter для обработки переключателей между окнами или страницами. Рэйчел называет это ApplicationViewModel, но по моему опыту он обычно должен делать больше, чем просто привязывать цель (например, получать сообщения, создавать Windows и т. д.), поэтому он технически более похож на традиционный Presenter или Controller.

В моем приложении мой Presenter начинается с CurrentViewModel. Presenter перехватывает всю связь между View и ViewModel. Одна из вещей, которую может выполнять ViewModel во время взаимодействия, возвращает новый ViewModel, что означает, что должна отображаться новая страница или новый Window. Presenter заботится о создании или перезаписывании View для нового ViewModel и установки DataContext.

Результат действия также может заключаться в том, что ViewModel является «полным», и в этом случае Presenter обнаруживает это и закрывает окно или выдает этот ViewModel с VM и возвращается к отображению предыдущей страницы.

ответил Scott Whitlock 17 42011vEurope/Moscow11bEurope/MoscowThu, 17 Nov 2011 06:11:23 +0400 2011, 06:11:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132