Используя MVVM в WPF, я должен запустить дочерние окна из кода View или ViewModel? - PullRequest
18 голосов
/ 07 мая 2011

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

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

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

Ответы [ 6 ]

19 голосов
/ 07 мая 2011

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

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-introducing-caliburn-micro.aspx

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

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

6 голосов
/ 07 мая 2011

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

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

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

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

3 голосов
/ 07 мая 2011

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

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

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

1 голос
/ 13 ноября 2016

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

0 голосов
/ 25 мая 2017

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

0 голосов
/ 07 мая 2011

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

...