Открыть диалог в WPF MVVM

У меня есть приложение, которому нужно открыть диалоговое окно с помощью кнопки, в которую пользователь вводит некоторую информацию.

На данный момент я делаю это так (что отлично работает)

  • Нажатие кнопки генерирует команду в ViewModel.
  • ViewModel вызывает событие, которое слушает контроллер.
  • Контроллер обрабатывает детали нового окна (например, View, ViewModel и модель) и открывает его (ShowDialog).
  • Когда окно закрывается, Контроллер добавляет результат к событиям и возвращается к ViewModel.
  • ViewModel передает информацию модели.

Есть много шагов, но все они имеют смысл и не требуют большого набора текста.

Код выглядит так (окно запрашивает имя пользователя)

ViewModel:

AskUserNameCommand = DelegateCommand(AskUserNameExecute);
...

public event EventHandler<AskUserEventArgs> AskUserName;

void AskUserNameExecute(object arg) {
    var e = new AskUserNameEventArgs();
    AskUserName(this, e);
    mModel.SetUserName(e.UserName);
}

Контроллер:

mViewModel.AskUserName += (sender,e) => {
    var view = container.Resolve<IAskUserNameView>();
    var model = container.Resolve<IAskUserNameModel>();
    var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model);
    if (dlg.ShowDialog() ?? false)
        e.UserName = model.UserName;
}

Мой вопрос в том, как горизонтальная коммуникация работает в шаблоне MVVM. Почему-то кажется неправильным позволять контроллеру участвовать в передаче данных между моделями.

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


person adrianm    schedule 26.11.2009    source источник
comment
Вы рассмотрели следующие вопросы? stackoverflow.com/questions/454868/ stackoverflow.com/ questions / 1667888 / wpf-mvvm-dialog-example stackoverflow.com/questions/1792814/   -  person Guge    schedule 27.11.2009
comment
Да, я смотрел на них, но все они рекомендуют шаблон широковещательной рассылки, чтобы решить что-то, что связано с экземпляром.   -  person adrianm    schedule 27.11.2009
comment
«Нажатие кнопки генерирует команду в ViewModel.», Что это означает? «ViewModel вызывает событие, которое слушает контроллер», какой контроллер ?!   -  person hyankov    schedule 29.12.2016


Ответы (5)


Мне не нравится большинство текущих предложений по той или иной причине, поэтому я подумал, что могу дать ссылку на почти идентичный вопрос с ответами, которые мне нравятся:

MVVM диалогового окна открытия файла

В частности, ответ Кэмерона МакФарланда - это именно то, что я делаю. Услуга, предоставляемая через интерфейс для обеспечения ввода-вывода и / или взаимодействия с пользователем, является подходящим вариантом по следующим причинам:

  • Это можно проверить
  • Он абстрагирует реализацию любых диалогов, так что ваша стратегия обработки таких вещей может быть изменена, не затрагивая составляющий код.
  • Не полагается на какие-либо шаблоны общения. Многие предложения, которые вы видите, полагаются на посредника, такого как агрегатор событий. Эти решения основаны на реализации двусторонней связи с партнерами по другую сторону посредника, что сложно реализовать и является очень слабым контрактом.
  • ViewModels остаются автономными. Я, как и вы, не чувствую себя хорошо, учитывая связь между контроллером и ViewModel. ViewModel должен оставаться автономным, если только по той причине, что это облегчает тестируемость.

Надеюсь это поможет.

person Anderson Imes    schedule 29.11.2009
comment
Спасибо, это заставило меня задуматься. Я не хочу вставлять ioc-контейнер в модель просмотра, поэтому я, вероятно, создам какой-нибудь IControllerService, который может вызывать модель просмотра. Будет намного чище, чем общение на основе событий, которое я получил сейчас. - person adrianm; 30.11.2009
comment
Если вы используете IoC, я бы просто объявил что-то вроде вашего IDialogService в качестве зависимости. Я обычно думаю о IoC как о каталоге сервисов, доступных для всех составляющих объектов. - person Anderson Imes; 01.12.2009

я использую этот подход для диалогов с mvvm .

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

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
person blindmeis    schedule 14.02.2011

Я сталкивался с подобными проблемами. Вот как я их решил и почему сделал то, что сделал.

Мое решение:

Моя MainWindowViewModel имеет свойство типа ModalViewModelBase, называемое Modal. Если моему коду требуется, чтобы определенное представление было модальным, он помещает на него ссылку в этом свойстве. MainWindowView наблюдает за этим свойством с помощью механизма INotifyPropertyChanged. Если Modal установлен на некоторую виртуальную машину, класс MainWindowView возьмет виртуальную машину и поместит ее в окно ModalView, где соответствующий UserControl будет отображаться с помощью магии DataTemplates, окно отображается с помощью ShowDialog. ModalViewModelBase имеет свойство DialogResult и свойство IsFinished. Когда модальная виртуальная машина устанавливает для IsFinished значение true, представление закрывается.

У меня также есть несколько специальных приемов для выполнения подобных интерактивных вещей из потоков backgroundworker, которые хотят запросить ввод данных у пользователя.

Мои рассуждения:

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

Механизм View, фактически запрещающий пользователю какие-либо другие действия, не должен выполняться с всплывающим окном и showdialog, возможно, вы поместите модальное представление в существующее окно, но отключите все остальные или что-то еще. Эта связанная с представлением логика принадлежит самому представлению. (То, что типичный дизайнер не может кодировать эту логику, кажется второстепенным. Нам всем иногда нужна помощь.)

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

person Guge    schedule 26.11.2009
comment
Это интересный способ, но я не могу сказать, как работает передача данных. Как пользовательский ввод попадает из модели диалога (представления) в модель основного (представления), когда диалоговое окно закрыто? - person adrianm; 27.11.2009
comment
MainViewModel по-прежнему имеет ссылку на DialogViewModel после закрытия диалогового окна. - person Guge; 27.11.2009
comment
хорошо, это более или менее то же самое, что и я, но вы делаете это в модели просмотра. - person adrianm; 27.11.2009

Я использовал EventAggregator из Prism v2 в аналогичных сценариях. Преимущество примитивов в том, что вам не нужно использовать весь фреймворк в своем приложении MVVM. Вы можете извлечь функциональность EventAggregator и использовать ее вместе с текущими настройками.

person Raj    schedule 26.11.2009
comment
EventAggregator хорош, но это широковещательный сервис. Я не могу найти простой способ настроить его для вызова определенного экземпляра слушателя. Предположим, пользователь открывает диалоговое окно, закрывает его и снова открывает. Теперь у меня есть два экземпляра view / viewmodel / model, которые прослушивают событие, пока GC не начнет очистку. Это можно решить, если слушатель откажется от подписки на событие, но это приведет к некоторому шаблону IDisposable в ViewModel / Model. - person adrianm; 27.11.2009
comment
@adrianm вы правы. Если вы хотите, чтобы ваше сообщение было доставлено конкретному экземпляру, агрегатор событий не подходит. - person Anderson Imes; 09.12.2009

Вы можете прочитать эту статью о MVVM. Он описывает, как контроллер может взаимодействовать с ViewModel:

http://waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Pattern&ProjectName=waf

person xdoo    schedule 29.11.2009
comment
Контроллер? В MVVM? - person Alexey Khrenov; 08.04.2021