|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
Добрый день. Есть концептуальный вопрос по разработке приложений с использованием паттерна MVVM. А именно открытие дочернего окна из основного, например по кнопке + как правило, нужно передавать данные из ViewModel-и первого окна во ViewModel второго и обратно. У меня есть два подхода к реализации этого сценария, но оба эти варианта кажутся мне неидеальными (а один из них вообще съедает много времени без видимой пользы). Я могу в подробностях их изложить здесь, мы побеседуем и придем к какому-то консенсусу. Просто на изложение уйдет много букв (времени) и не хотелось бы набирать все впустую, а в результате никто не ответит. В общем, если кто-то считает себя опытным применителем паттерна MVVM и, возможно, сам многократно сталкивался с такой задачей — дайте знать и я распишу все в деталях. С уважением. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2014, 11:11 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
Вот расписал. Есть ViewOne и соответствующая модель ViewModelOne, ViewTwo и соответствующая модель ViewModelTwo. ViewOne и ViewTwo – окна. Типичная ситуация. Во ViewOne есть кнопка, по нажатию на которую открывается окно ViewTwo. Т.е. есть команда во ViewModelOne, назовем ее OpenViewTwoCommand, привязанная к событию Click кнопки. Команда в свою очередь вызывает метод OpenViewTwoMethod и в этом методе «открывается» окно. Вариант первый. В методе OpenViewTwoMethod создается экземпляр ViewModelTwo и ViewTwo. Данные из ViewModelOne передаются во ViewModelTwo через свойства. Точно так же через свойства их удобно считывать, когда окно будет закрыто. Недостатки: Для ViewTwo невозможно проинициализировать свойство Owner, ведь ViewModelOne ничего не знает о ViewOne. Лечится хранением в ViewModelOne указателя на ViewOne (проинициализировать можно на событие Loaded окна ViewOne). Но тут возникает вопрос о корректности такого подхода, не противоречит ли он принципам MVVM? Вариант второй. Где то на stackoverflow я вычитал, что кошерно когда View открывает View, а Модель создает Модель. Суть в следующем. Жмем на кнопку во ViewOne, срабатывает команда в ViewModelOne, создается ViewModelTwo, а так же сообщение специального типа, в него помещается ViewModelTwo и шлется сообщение окну ViewOne посредством Messenger.Default.Send. ViewOne регистрируется на получение сообщения и при получении оного открывает ViewTwo. Идея показалась абсолютно логичной и очень понравилась. Настолько что я стал везде применять этот подход, но, как говорится, «все было слишком хорошо, чтобы быть правдой» Недостатки: 1) Самый очевидный – необходимость создания типов сообщений. Если на форме 10 кнопок , открывающих разные окна – 10 типов сообщений. Несложно, но время то ест. 2) Менее очевидный . Если мне нужно по закрытию ViewTwo выполнять какие-то действия с данными, которые находятся во ViewModelTwo – нужно во ViewModelOne отслеживать событие закрытия окна. Т.е. объявлять обработчик событий, возможно еще и создавать специальный тип-хелпер для аргументов события + делегат. 3) Следует из второго. Пусть OpenViewTwoMethod – метод, в котором открывается ViewTwo. private void OpenViewTwoMethod() { // обработка данных ViewModelOne, получили DataViewModelOne - не суть какие данные // открытие окна ViewTwo } /// <summary> /// Событие закрытия окна ViewTwo /// </summary> private void ViewTwoClosed() { // а вот тут мне нужно еще что-то сделать с DataViewModelOne, учитывая данные из ViewModelTwo // получается мне нужно дополнительно хранить DataViewModelOne в ModelViewOne } А вы что посоветуете? :) ... |
|||
:
Нравится:
Не нравится:
|
|||
28.07.2014, 13:19 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
monstrilla, Здесь на мой взгляд представлен наилучший вариант решения это проблемы. А здесь похожаля логика, но максимально упрощенная. ... |
|||
:
Нравится:
Не нравится:
|
|||
07.08.2014, 02:31 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
monstrilla, в 1й вьехе добавляем команды, например: Код: c# 1.
далее создаем класс для команды: Код: c# 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37.
далее в конструкторе 1й вьюхи: Код: c# 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
14.08.2014, 12:11 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
iMrTidy, спасибо, очень интересно, разбираю. Супер_Пав, жесть какая-то :) ... |
|||
:
Нравится:
Не нравится:
|
|||
20.08.2014, 16:46 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
Разобрал. Оно, конечно работает, но на мой взгляд излишне усложнено. Во-первых можно обойтись безо всех интерфейсов, т.к. они не используются как интерфейсы. По сути, существуют только для проформы и на них завязана логика работы ServiceLocator-а. О этом типе см ниже. OpenFileDialogViewModel, FolderBrowserDialogViewModel - просто классы, объекты которых используются для инициализации виндовых окон, т.е. если инитить окна напрямую - можно обойтись и без них. Кстати, окошки типа MessageBox именно так и инитятся. Посему непонятно, почему автор по аналогии не запилил тип MessageBoxViewModel и интерфейс IMessageBoxViewModel. OpenFileDialog, FolderBrowserDialog - не более чем обертки над виндовыми диалоговыми окнами. Зачем они, если можно напрямую создать экземпляры окон System.Windows.Forms.OpenFileDialog и System.Windows.Forms.FolderBrowserDialog? Вся соль, сосредоточена в классе DialogService. Его можно просто запилить как синглтон (тогда надобность в типе ServiceLocator отпадает вообще). В общем, считаю, что можно написать в 3 раз более простой и меньший по объему код, который будет делать в точности то же самое. Возможно, я чего то не знаю :) ... |
|||
:
Нравится:
Не нравится:
|
|||
21.08.2014, 17:12 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
monstrillaВозможно, я чего то не знаю :)Меньше знаешь - крепче спишь... :-) monstrillaРазобрал. Оно, конечно работает, но на мой взгляд излишне усложнено. Во-первых можно обойтись безо всех интерфейсов, т.к. они не используются как интерфейсы. По сути, существуют только для проформы и на них завязана логика работы ServiceLocator-а. О этом типе см ниже.Мир в наше время повёрнут на подстановке альтернативной реализации сервисов на этапе тестирования. Отсюда фанатичная тяга к интерфейсам и диконтейнерам. monstrillaВ общем, считаю, что можно написать в 3 раз более простой и меньший по объему код, который будет делать в точности то же самое.Часто так и есть, но не всегда. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.08.2014, 17:23 |
|
Открытие дочернего окна, передача данных между ViewModel-ями окон
|
|||
---|---|---|---|
#18+
Алексей К, Да, я совершенно не использую юнит-тесты, и даже не знаю(пока) как они работают :) Тестируем работоспособность функционала методом тыка в разные места интерфейса. Наверное, вся эта "лишняя" обвязка для юнит-тестов и нужна. ... |
|||
:
Нравится:
Не нравится:
|
|||
21.08.2014, 17:41 |
|
|
start [/forum/topic.php?fid=21&fpage=21&tid=1441064]: |
0ms |
get settings: |
10ms |
get forum list: |
12ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
42ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
46ms |
get tp. blocked users: |
2ms |
others: | 9ms |
total: | 144ms |
0 / 0 |