Пример # 1: у меня есть представление, отображаемое в моем приложении MVVM (давайте использовать Silverlight для целей обсуждения), и я нажимаю кнопку, которая должна перенести меня на новую страницу.
Пример # 2: В этом же представлении есть еще одна кнопка, которая при нажатии открывает окно подробностей в дочернем окне (диалоге).
Мы знаем, что будут объекты Command, представленные нашей ViewModel, привязанными к кнопкам с методами, которые реагируют на щелчок пользователя. Но что тогда? Как мы закончим действие? Даже если мы используем так называемый NavigationService, о чем мы говорим?
Чтобы быть более конкретным, в традиционной модели View-first (такой как схемы навигации на основе URL-адресов, такие как в Интернете или встроенной инфраструктуре навигации SL), объектам Command необходимо знать, какой View будет отображаться следующим. Это, кажется, пересекает черту, когда дело доходит до разделения проблем, продвигаемых шаблоном.
С другой стороны, если кнопка не связана с объектом Command и ведет себя как гиперссылка, правила разметки могут быть определены в разметке. Но хотим ли мы, чтобы представления управляли потоком приложений и не были ли навигация просто еще одним типом бизнес-логики? (Я могу сказать да в некоторых случаях и нет в других.)
Для меня утопическая реализация шаблона MVVM (и я слышал, что другие утверждают это) состояла бы в том, чтобы иметь ViewModel, подключенный таким образом, чтобы приложение могло работать без головы (то есть без Views). Это обеспечивает большую площадь поверхности для тестирования на основе кода и делает представления настоящей оболочкой для приложения. И моя ViewModel не должна заботиться, отображается ли она в главном окне, плавающей панели или дочернем окне, не так ли?
В соответствии с этим подходом во время выполнения это зависит от какого-то другого механизма, связывающего то, что View должно отображаться для каждой ViewModel. Но что, если мы хотим поделиться View с несколькими ViewModels или наоборот?
Таким образом, учитывая необходимость управлять отношениями View-ViewModel, чтобы мы знали, что отображать, когда наряду с необходимостью перемещаться между представлениями, включая отображение дочерних окон / диалогов, как мы действительно выполняем это в шаблоне MVVM?
источник
DataTemplateSelector
, что я обычно использую для приложений Silverlight. 2) Я использовал это во многих-многих ситуациях раньше. Например, одна ViewModel может иметь несколько представлений, или одно представление может быть связано с несколькими представлениями. Для примера первого см. Rachel53461.wordpress.com/2011/05/28/… . Для последующего вам просто нужно указать, что несколько ViewModels сопоставляются с одним и тем же представлением в вашем DataTemplateSelector.CurrentPages
4) Еще раз, это был лишь базовый пример. В действительности все мои PageViewModel основаны на каком-то базовом классе, поэтому моя ShellViewModel работает только с базовым классом или интерфейсом, таким какIPageViewModel
. Действительно, самая большая грязная часть отображения - это DataTemplateSelector, который должен был бы отобразить 40 видов на 40 моделей представления.Ради закрытия я думал, что опубликую направление, которое я наконец выбрал, чтобы решить эту проблему.
Первым решением было использование встроенной в Silverlight инфраструктуры навигации по страницам. Это решение было основано на нескольких факторах, включая знание того, что этот тип навигации переносится 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. В результате установка свойства обновляет источник и запускает навигацию.
Возвращаясь к NavigationService. Метод NavigateTo принимает имя целевой страницы. Чтобы убедиться, что у ViewModel нет проблем с пользовательским интерфейсом, используемое имя - это имя ViewModel для отображения. Я на самом деле создал перечисление, которое имеет поле для каждой навигационной ViewModel в качестве помощника и для устранения магических строк во всем приложении. Функция отображения, о которой я упоминал выше, удалит суффикс «ViewModel» из имени, добавит «Page» к имени и задаст полное имя «Views {Name} Page.xaml».
Так, например, чтобы перейти к просмотру сведений о клиенте, я могу позвонить:
Значением CustomerDetails является «CustomerDetailsViewModel», которое сопоставлено с «Views \ CustomerDetailsPage.xaml».
Прелесть этого подхода в том, что пользовательский интерфейс полностью отделен от ViewModels, но у нас есть полная поддержка навигации. Тем не менее, теперь я могу изменить свое приложение и в любое время, когда оно будет изменено.
Надеюсь, объяснение поможет.
источник
Подобно тому, что сказала Рэйчел, мое приложение, в основном MVVM, имеет функцию
Presenter
для переключения между окнами или страницами. Рэйчел называет этоApplicationViewModel
, но, по моему опыту, это обычно должно делать больше, чем просто цель привязки (например, получать сообщения, создавать Windows и т. Д.), Так что технически это больше похоже на традиционноеPresenter
илиController
.В моем приложении мой
Presenter
начинается сCurrentViewModel
.Presenter
Перехватывает все коммуникации междуView
иViewModel
. Одна из вещей, которуюViewModel
можно сделать во время взаимодействия, это вернуть новуюViewModel
, что означает, чтоWindow
должна отображаться новая страница или новая . ThePresenter
заботится о создании или перезаписиView
для новогоViewModel
и настройкеDataContext
.Результатом действия также может быть то, что
ViewModel
«завершено», и в этом случаеPresenter
обнаруживает это и закрывает окно, или выталкивает этоViewModel
из стека виртуальных машин и возвращается к отображению предыдущей страницы.источник
Presenter
просто вставляет возвращаемоеViewModel
в визуальное дерево, а WPF захватывает соответствующееView
, подключаетDataContext
и помещает его в визуальное дерево. Вы можете сделать это, используяDataTemplate
s, которые объявляют, какойViewModel
тип они отображают, или вы можете создать собственный селектор шаблонов данных. Это все еще в сфере возможностей WPF.