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

Используя MVVM в WPF, должен ли я запускать дочерние окна из View code позади или ViewModel?

Я был озадачен этим некоторое время. Я пишу довольно большое приложение RibbonWindow WPF, используя шаблон MVVM. На экране есть меню RibbonBar вверху, а остальная часть отображает различные виды. Некоторые представления содержат другие виды, и некоторые из них имеют кнопки, запускающие дочерние Windows.

До сих пор я делал это из файла View за файлом, но я знаю, что при использовании MVVM эти файлы должны быть пустыми. Я мог бы переместить код запуска дочернего окна в ViewModel, но тогда мне понадобится ссылка на главный RibbonWindow (для установки как владелец дочернего окна), и это кажется неправильным.

Было бы полезно получить любые советы или советы о том, как это обычно достигается с помощью MVVM.

4b9b3361

Ответ 1

Я обычно справляюсь с этим, создавая своего рода WindowViewLoaderService. Когда ваша программа инициализируется, вы регистрируете свое Window и ваши ViewModels с кодом, похожим на этот:

WindowViewLoaderService.Register(TypeOf(MainWindowView), TypeOf(MainWindowViewModel));
WindowViewLoaderService.Register(TypeOf(MyWindowView), TypeOf(MyWindowViewModel));

Затем, когда вы можете, например, позвонить в эту службу из вашей ViewModel, и все, на что вам нужно ссылаться - это ваша другая ViewModel. Например, если вы находитесь в MainWindowViewModel, у вас может быть такой код:

var myChildWindowVM = new MyWindowViewModel();
WindowViewLoaderService.ShowWindow(myChildWindowVM);

Затем WindowViewLoaderService будет искать, какой View связан с указанной ViewModel, которую вы передали. Он создаст это представление, установит его DataContext равным ViewModel, который вы передали, и затем отобразит представление.

Таким образом, ваши ViewModels никогда не узнают ни о каких представлениях.

Вы можете довольно легко свернуть один из этих сервисов. Все, что ему нужно сделать, это сохранить словарь, ключом которого будет ваш ViewModelType, а значением - ваш ViewType. Метод Register добавляет ваш словарь, а метод ShowWindow ищет правильное представление на основе переданной ViewModel, создает представление, устанавливает DataContext и затем вызывает Show для него.

Большинство фреймворков MVVM предоставляют что-то подобное прямо из коробки. Например, у Caliburn есть гладкий, который просто использует соглашение об именах, он называется ViewLocator в этой платформе. Вот ссылка, которая обобщает: http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introduction-caliburn-micro.aspx

Cinch, с другой стороны, называет его WPFUIVisualizerService, который вы можете увидеть в действии здесь: http://www.codeproject.com/KB/WPF/CinchIII.aspx

Это должно помочь вам начать работу.

Ответ 2

Ну, одно замечание для начала состоит в том, что "отсутствие кода AT ALL в кодировке" на самом деле является "мифом". Если вы хотите быть прагматичным, и вы видите, что наличие некоторого кода (насколько это было бы возможно, было бы лучше), облегчит вам жизнь и решит вашу проблему, тогда вы должны пойти с этим.

Однако в этой ситуации на самом деле существуют некоторые слабо связанные способы сделать это. У вас может быть служба, которая будет взаимодействовать для вас. Вы инициируете взаимодействие с пользователем из ViewModel, служба позаботится об этом (например, показывая ChildWindow) и возвращает ответ пользователю. Эту услугу можно легко издеваться за тестирование. И он может быть протестирован отдельно.

То есть, если вы хотите делать все сами. Если вы хотите, чтобы фреймворк делал тяжелую работу для вас, вы можете проверить функциональность InteractionRequest, предлагаемую Призмой. Здесь статья MSDN, в которой рассказывается о адаптированных сценариях MVVM, который включает раздел Шаблоны взаимодействия с пользователем. Это так, как я это делаю, и это довольно просто, элегантно и просто.

Надеюсь, что это поможет:)

Ответ 3

Чтобы ответить Мэтту на один шаг дальше, вы можете использовать все свое представление как пользовательский элемент управления. Затем создайте ViewContainer, который представляет собой окно с вашими шаблонами данных (как вы описали).

Затем вы просто отправляете viewmodel, который хотите открыть, в службу окна, которая устанавливает DataContext. Затем служба откроет окно, и contentcontrol разрешит правильное представление для модели просмотра.

Это означает, что вся регистрация выполняется в XAML, и служба окна просто знает, как это сделать... открыть и закрыть окна.

Ответ 4

Это старый пост, но, возможно, это поможет кому-то в пути: я использую MVVM и поднимаю события для открытия дочерних окон из ViewModel обратно в представление. Единственный код позади - это обработка события, открытие окна, установка владельца дочернего окна и многое другое. В viewmodel, если обработчик события имеет значение NULL, он не подписывается на представление и не запускается. VM не знает о представлении. Код также довольно прост и занимает всего несколько строк.

Ответ 5

В этой ситуации View должен обрабатывать открытие дочерних окон. Тем не менее, ViewModel может управлять созданием окон, но вызывать в View для создания новой Windows. Это сохранит логику шаблона MVVM: ViewModel имеет "мозги", но не участвует в создании определенного окна.

Ответ 6

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