[WPF] События от ViewModel к View
От: Fortnum  
Дата: 21.10.10 11:15
Оценка:
События от View к ViewModel — это команды. А как общепринято делать наоборот, если инициатор события ModelView? Есть какие-нибудь распространенные фреймворки, решающие эту проблему (в Caliburn не нашел)?

Я сейчас делаю кажется тупо: создаю интерфейс IMyInterface с событиями и состоянием, а также соответствующий ему Attached Property. В последнем в DataContextChanged пытаюсь получить у ModelView этот интерфейс, привести состояние View к текущему состоянию ModelView и подписываюсь на события. Уже такая ооочень нехилая библиотека этих интерфейсов/attached propert'ей нарисовалась, хочется создать генеральное решение.
Re: [WPF] События от ViewModel к View
От: Codechanger Россия  
Дата: 21.10.10 11:42
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>События от View к ViewModel — это команды. А как общепринято делать наоборот, если инициатор события ModelView? Есть какие-нибудь распространенные фреймворки, решающие эту проблему (в Caliburn не нашел)?


F>Я сейчас делаю кажется тупо: создаю интерфейс IMyInterface с событиями и состоянием, а также соответствующий ему Attached Property. В последнем в DataContextChanged пытаюсь получить у ModelView этот интерфейс, привести состояние View к текущему состоянию ModelView и подписываюсь на события. Уже такая ооочень нехилая библиотека этих интерфейсов/attached propert'ей нарисовалась, хочется создать генеральное решение.


Сценарий подобного события приведите, пожалуйста.
Re[2]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 21.10.10 12:08
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Сценарий подобного события приведите, пожалуйста.


Много можно привести примеров по тому принципу, что один View не знает ничего о другом, но их ViewModel'и знают. Например, имеем во View1 компонент WebBrowser. Этим View1 управляет ModelView1. Есть View2 с управлением навигацией, под ним ModelView2, который имеет ссылку на ModelView1. View2 о View1, естественно, ничего не знает (более того, они даже в разных окнах и не могут друг другу кинуть мессагу в любом случае даже если очень захотеть), то есть все управление проходит по уровню ModelView (ModelView2 -> ModelView1). Как ModelView1 будет управлять навигация WebBrowser'а во View1?

Также еще возможны такие примеры, где ModelView получает побуждение к действию от внешних сил, например от WCF- или COM-клиента. Проблема аналогичная. Если у ModelView меняется какой-нибудь property или коллекция — нет проблем, на помощь приходит биндинг INotifyPropertyChanged + INotifyCollectionChanged. Но что если во View надо вызвать какой-нибудь метод или поднять Routed Event в управляемом им View, чтобы этот RoutedEvent пошел по маршруту по дереву, например выше, в другой View, куда этот View более низкого уровня включен?

Короче, я представляю себе горизонтальные связи на двух уровнях — View и ViewModel. На уровне View эти связи решаются путем RoutedEvents, но не всегда возможны (разъдиненные деревья), либо просто неудобны (маршруты эти такая бяка, и out-of-box их нет, писать надо), чем на уровне ModelView, где это происходит простым удержанием взаимных ссылок, в т.ч. подпиской на события. Все это хорошо работает, но в параллельных плоскостях. От View к ModelView сигналы хорошо ходят через команды. А вот обратная сторона от ModelView к View почему-то создается такое впечатление, что всеми игнорируется (книги, статьи и т.п.).
Re[3]: [WPF] События от ViewModel к View
От: Codechanger Россия  
Дата: 21.10.10 13:46
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, Codechanger, Вы писали:


C>>Сценарий подобного события приведите, пожалуйста.


F>Много можно привести примеров по тому принципу, что один View не знает ничего о другом, но их ViewModel'и знают. Например, имеем во View1 компонент WebBrowser. Этим View1 управляет ModelView1. Есть View2 с управлением навигацией, под ним ModelView2, который имеет ссылку на ModelView1. View2 о View1, естественно, ничего не знает (более того, они даже в разных окнах и не могут друг другу кинуть мессагу в любом случае даже если очень захотеть), то есть все управление проходит по уровню ModelView (ModelView2 -> ModelView1). Как ModelView1 будет управлять навигация WebBrowser'а во View1?


Ну я как бы вижу BrowserViewModel, в которой есть NavigationViewModel и PresentationViewModel. Таким образом, все события навигации отражаются на свойства VM(или команды), ну и дальше идет логика в коде BrowserViewModel по выставлению нужных свойств у конкретных ViewModel. Еще как вариант — под навигацию и показ подкладывать один и тот же ViewModel
Re[4]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 21.10.10 14:13
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Ну я как бы вижу BrowserViewModel, в которой есть NavigationViewModel и PresentationViewModel. Таким образом, все события навигации отражаются на свойства VM(или команды), ну и дальше идет логика в коде BrowserViewModel по выставлению нужных свойств у конкретных ViewModel.


Стоп. Маленькая тонкость — не события навигации должны отражаться на свойствах ViewModel, а события во ViewModel на навигации.

Опишу конкретно. Есть WPF-приложение. В нем должно быть два окна: одно прижато к краю экрана (Application Bar), и на нем размещено пять кнопок, по нажатию каждой из которых WebBrowser (без элементов управления — просто ActiveX в рамочке) во втором, плавающем по экрану, окне должен идти по адресу в соответствии с нажатой кнопкой. В дополнение к пяти кнопкам навигации в первом окне есть еще три: назад, вперед и обновить. Плюс навигация — это не просто смена свойства URL, но также еще должен быть отправлен ряд HTTP-заголовков (т.е. не удастся просто привязать проперти URL у View к проперти URL у ViewModel).

C>Еще как вариант — под навигацию и показ подкладывать один и тот же ViewModel


ОК. Так и будем считать — под обоими этими окнами один ViewModel.

Вот лично я не нахожу лучшего варианта как определить свой собственный интерфейс IWebBrowserController:

interface IWebBrowserController
{
  event EventHandler Navigate;
  event EventHandler Back;
  event EventHandler Forward;
  event EventHandler Refresh;
}


Реализовать этот IWebBrowserController у ViewModel. Создать статический класс WebBrowserController с DependencyProperty bool IsActive = "True", который насадить на элемент WebBrowser'а в XAML'е, и установить в метаданных этого IsActiveProperty делегат PropertyChangedCallback на метод, в котором подпиаться на событие WebBrowser.DataContextChanged и при смене этого датаконтекстного объекта попытаться получить у него IWebBrowserController и подписаться на эти четыре события. Бр-р-р-р... В общем-то я сейчас так и делаю Полдня сегодня искал какое-нибудь генеральное решение — не нашел. Есть мысль создать некий базовый класс такого подписчика, но удивляет, что реально никто об этом не пишет, или я не могу найти.

Как вы относитесь к описанному выше?
Re[5]: [WPF] События от ViewModel к View
От: GlebZ Россия  
Дата: 21.10.10 14:23
Оценка: 3 (1)
Здравствуйте, Fortnum, Вы писали:

F>Как вы относитесь к описанному выше?

Положительно, но есть один вопрос. Вьюха всегда знает о ВьювМодели. Это обратная зависимость вредна. Подкладываение различных вьювмоделей под одну и ту же вьюху — процесс весьма редкий. Даже скажу чрезвычайно редкий. Поэтому непонятно зачем вывод эвентов через интерфейс, а не напрямую.
Re[6]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 21.10.10 14:44
Оценка:
Здравствуйте, GlebZ, Вы писали:

F>>Как вы относитесь к описанному выше?

GZ>Положительно, но есть один вопрос. Вьюха всегда знает о ВьювМодели. Это обратная зависимость вредна. Подкладываение различных вьювмоделей под одну и ту же вьюху — процесс весьма редкий. Даже скажу чрезвычайно редкий. Поэтому непонятно зачем вывод эвентов через интерфейс, а не напрямую.

Это потому что в C# наследовать можно только от одного родителя, а ViewModel может использоваться для управления не только WebBrowser'ом на View, но и для управления другими элементами, в частности, я использую еще ряд интерфейсов для управления окнами. Например, у меня есть интерфейс IWindowSetPosController, который позволяет ViewModel'и управлять положением окна, под которое он подсажен. Это нужно для синхронизации Z-порядка между окнами — у меня их много, порядка 20 штук одновременно может быть открыто. Фактически у меня получился свой менеджер окон, своеобразный MDI, т.к. я открытые окна на панель задач не вывожу, у меня своя панель задач. А за Z-порядком надо следить, а это возможно только при помощи вызова функций WinAPI, в частности, SetWindowPos с параметром hwndInsertAfter. А сведения о Z-порядке находятся во ViewModel. Так и получается, что мой ViewModel реализует два интерфейса IWebBrowserController и IWindowSetPosController, и он одновременно является DataContext'ным объектом для Window и для WebBrowser'а. На самом деле там еще сложнее, потому что у меня группы окон работают каждая в своем UI-потоке, т.к. в них находятся не мои ActiveX, которые иначе тормозят весь GUI, и иерархия получается вообще жуткая — без интерфейсов не обойтись.

Значит придется мне что-то самому изобретать? Блин, неужели никто про это даже статью в блоге не написал?.. Я удивляюсь.
Re[7]: [WPF] События от ViewModel к View
От: GlebZ Россия  
Дата: 21.10.10 15:45
Оценка:
Здравствуйте, Fortnum, Вы писали:

Понятненько. Тогда советую посмотреть Composite WPF(Prizm), в частности Event Aggregator(давно его смотрел, счас похоже что-то в нем изменилось). Там также есть модели MVP, но честно говоря сходу не сильно врубаюсь чем они могут тебе помочь в уменьшении кодокодирования. Разве что они более чистые чем MVVM по умолчанию. Вобщем, смотри, любуйся — весьма возможно найдешь полезное именно для твоей задачи.
Re[8]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 02:04
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Понятненько. Тогда советую посмотреть Composite WPF(Prizm), в частности Event Aggregator(давно его смотрел, счас похоже что-то в нем изменилось). Там также есть модели MVP, но честно говоря сходу не сильно врубаюсь чем они могут тебе помочь в уменьшении кодокодирования. Разве что они более чистые чем MVVM по умолчанию. Вобщем, смотри, любуйся — весьма возможно найдешь полезное именно для твоей задачи.


Да я уже несколько дней задумываюсь, а не стоит ли сменить паттерн IMyInterface/MyAttachedProperty на Медиатор. Сейчас вот прочитал этот Prism, и ничего революционного для решения своей проблемы не обнаружил — Event Aggregator, получается, — это тот же медиатор встроенный в контейнер приложения. В общем-то везде речь идет о том, что его назначение — развязывание модулей (плагинов). Конечно, можно использовать и его, но только чем принципиально это будет отличаться от подхода IMyInterface/MyAttachedProperty? Мой ModelView пишется под вполне конкретный View (или наоборот), поэтому такой decouple'инг (через медиатор) здесь не даст никаких преимуществ: в части событий экземпляр ModelView, подсунутый в DataContext экземпляра View, по сути, представляет собой контейнер для этого View. Другим View'хам и другим ModelView'хам абсолютно начхать на то как общаются между собой эта данная пара View/ModelView, т.к. все связи между ними идут либо на уровне View через RoutedEvent'ы и RoutedCommand'ы (об этом ниже), либо на уровне зависимостей между экземплярами ModelView, удержанием взаимных ссылок. Мне такая развязка между компонентами моего приложения только лишь ради самой развязки просто тупо не нужна, т.к. требования иметь именно louse couple (взаимно между _всеми_ View'хами и ModelView'хами) не стоит абсолютно (это литое приложение), а — главное — никакого генерального решения в части инкапсуляции boilerplate-кода подписки/отписки от событий контроллеров этот EventAggergator собой не представляет (как, например, представляют собой Actions и Commands в Caliburn'е). Кстати, в примерах к EventAggregator'у в Prism идет связь через этот медиатор двух контроллеров, а не двух View'юх.

При использовании глобального медиатора, кстати, становится возможным управление данным View из другого ModelView (в пределах одного модуля), что абсолютно недопустимо, т.к. все может выйти из под контроля и замучаешься искать где Вот Commanding реализован же без всяких медиаторов, хотя тоже можно было бы. Чё-то я задумался... либо я нашел себе несуществующую проблему, либо я даже не знаю что... пойду поразмышляю пока.

Да, кстати, насчет RoutedEvent'ов и RoutedCommand — для чего я еще использую эту связку IMyInterface/MyAttachedProperty, так это для того, чтобы данный ModelView мог обмениваться информацией с другими ModelView'хами, на которые у него нет ссылки! Связь ModelView'юх определяется лишь композицией View'юх. Идея такая, что ModelView поднимает событие, которое улавливается его View'хой (а точнее насаженным на эту View'ху Attached Property). Увидев это событие View'ха поднимает в своем узле RoutedEvent (или RoutedCommand). Этот RoutedEvent идет по дереву вверх-вниз (или можно свой маршрут, я так понимаю прописать, если реализовать свой Routed Event/Сommand), и затрагивает другие View'хи, которые подсажены на свои ModelView'хи, которые с первоначальной ModelView'хой никак не связаны. По сути, тот же медиатор, только через Visual-tree
Re[5]: [WPF] События от ViewModel к View
От: Codechanger Россия  
Дата: 22.10.10 06:02
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Опишу конкретно. Есть WPF-приложение. В нем должно быть два окна: одно прижато к краю экрана (Application Bar), и на нем размещено пять кнопок, по нажатию каждой из которых WebBrowser (без элементов управления — просто ActiveX в рамочке) во втором, плавающем по экрану, окне должен идти по адресу в соответствии с нажатой кнопкой. В дополнение к пяти кнопкам навигации в первом окне есть еще три: назад, вперед и обновить. Плюс навигация — это не просто смена свойства URL, но также еще должен быть отправлен ряд HTTP-заголовков (т.е. не удастся просто привязать проперти URL у View к проперти URL у ViewModel).



F>Как вы относитесь к описанному выше?


1. Написать команду, которая осуществляет переходы по URL, отправку http-заголовков и т.д.В качестве параметра команды, естественно, должна выступать ViewModel.
2. Команду разместить во ViewModel.
3. ViewModel для обоих окон использовать одну и ту же.
4. Profit.
Re[6]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 06:20
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>1. Написать команду, которая осуществляет переходы по URL, отправку http-заголовков и т.д.В качестве параметра команды, естественно, должна выступать ViewModel.


Ты, наверное, имеешь в виду в качестве параметра команды должен выступать View?
Re: [WPF] События от ViewModel к View
От: MxMsk Португалия  
Дата: 22.10.10 06:54
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>События от View к ViewModel — это команды. А как общепринято делать наоборот, если инициатор события ModelView? Есть какие-нибудь распространенные фреймворки, решающие эту проблему (в Caliburn не нашел)?

Я делаю обычное событие во ViewModel и в реализации View, в сеттере модели, подписываюсь на это событие. Вариант мне не нравится, а над альтернативой пока не думал
Re[7]: [WPF] События от ViewModel к View
От: Codechanger Россия  
Дата: 22.10.10 07:13
Оценка:
Здравствуйте, Fortnum, Вы писали:

F>Здравствуйте, Codechanger, Вы писали:


C>>1. Написать команду, которая осуществляет переходы по URL, отправку http-заголовков и т.д.В качестве параметра команды, естественно, должна выступать ViewModel.


F>Ты, наверное, имеешь в виду в качестве параметра команды должен выступать View?


Зачем View?View всего лишь является отображением того, что есть во ViewModel.Имхо, завести в ней свойство URL не очень сложно.
Re[8]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 07:23
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>>>1. Написать команду, которая осуществляет переходы по URL, отправку http-заголовков и т.д.В качестве параметра команды, естественно, должна выступать ViewModel.

F>>Ты, наверное, имеешь в виду в качестве параметра команды должен выступать View?
C>Зачем View?View всего лишь является отображением того, что есть во ViewModel.Имхо, завести в ней свойство URL не очень сложно.

Тогда я не понял. Если команда во ViewModel, ViewModel одна и та же, зачем команде еще и в параметре передавать ту же ViewModel?..
Re[2]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 07:26
Оценка:
Здравствуйте, MxMsk, Вы писали:

F>>События от View к ViewModel — это команды. А как общепринято делать наоборот, если инициатор события ModelView? Есть какие-нибудь распространенные фреймворки, решающие эту проблему (в Caliburn не нашел)?

MM>Я делаю обычное событие во ViewModel и в реализации View, в сеттере модели, подписываюсь на это событие. Вариант мне не нравится, а над альтернативой пока не думал

Уже хорошо, что я не маньяк и не один использую события ViewModel-to-View

А обработчик события ViewModel находится у тебя в code-behind View'юхи?
Re[3]: [WPF] События от ViewModel к View
От: MxMsk Португалия  
Дата: 22.10.10 07:43
Оценка: 1 (1)
Здравствуйте, Fortnum, Вы писали:

F>Уже хорошо, что я не маньяк и не один использую события ViewModel-to-View

Ууу, я тебя уверяю, на Stackoverflow полно было таких вопросов, и все советы, что я встречал, сводились именно к такой архитектуре — использование обычных event-ов от модели.

F>А обработчик события ViewModel находится у тебя в code-behind View'юхи?

Да. Я не нашел для себя плюсов в выносе обработчика за пределы View. Возможно, когда у нас будет по несколько View на одну модель, отделим. Но пока такого нет, а сама обработка событий зачастую связана с необходимостью манипулировать какими-нибудь контролами, заданными в XAML. Тут уж фиг чего в общий слой вынесешь.

Вариантом отказа от событий в модели, может быть выставление через интерфейс нужных методов View. Можно сказать, что мы делаем обработчики частью контракта. Но это, конечно, неудобно, потому что требует держать в модели ссылку на представление.
Re: [WPF] События от ViewModel к View
От: Vladek Россия Github
Дата: 22.10.10 07:49
Оценка: 12 (1)
Здравствуйте, Fortnum, Вы писали:

F>События от View к ViewModel — это команды. А как общепринято делать наоборот, если инициатор события ModelView? Есть какие-нибудь распространенные фреймворки, решающие эту проблему (в Caliburn не нашел)?


F>Я сейчас делаю кажется тупо: создаю интерфейс IMyInterface с событиями и состоянием, а также соответствующий ему Attached Property. В последнем в DataContextChanged пытаюсь получить у ModelView этот интерфейс, привести состояние View к текущему состоянию ModelView и подписываюсь на события. Уже такая ооочень нехилая библиотека этих интерфейсов/attached propert'ей нарисовалась, хочется создать генеральное решение.


Я просто делаю нужные свойства зависимостей во View и пишу конкретный код в обработчиках изменений этих свойств. Если поведение нужно распространить на несколько View — делаю свойства вложенными.

Конкретно по задаче: сделал бы свойства NavigationState и HttpHeaders во View и привязал бы к ним ViewModel. При изменении этих свойств View делал бы всю работу по изменению себя.

Никаких интерфейсов, ViewModel — это всегда конкретный класс, содержащий прикладную логику — это он сам обращается к всяким разным сервисам через интерфейсы.
Re[9]: [WPF] События от ViewModel к View
От: GlebZ Россия  
Дата: 22.10.10 07:53
Оценка:
Здравствуйте, Fortnum, Вы писали:

Давай немного разберемся.
1. Я PRISM дал не потому что в нем содержался ответ. А потому, что не зная ньюансов (не смотря на то, что ты много и содержательно описал), возможно ты найдешь что-то полезное. Как ты уже заметил, призма имеет конкретную направленность — развязывание зависимости на уровне компонентов как программных (VM и т.п.), так и визуалки.
2. Твой вариант мне действительно не очень. И проблема в том, что если ты подписываешься к статическому объекту, то ты обязан от него во время отвязаться. Иначе утечка памяти. Согласись — не слишком приятная обязанность, хотя и не смертельная.
3. Event Aggregator — решает вышеописанную проблему, но как ты уже заметил, он предназначен для взаимодействия уровня ViewModel и ниже. Но никак не для вьюх. Кстати — Event Aggregator прежде всего не прокидывание состояния, а лишь уведомление прозошедшем событии. Состояние обычно лежит либо во вьювмоделях, если оно не должно быть глобальным, либо в чем то вида репозитория. Вообще, мне эта модель импонирует и использовалась в проекте, правда не связанным с WPF.
4. Наверно всё таки мы делаем муху из слона, и это обусловлено тем, что event в программировании используется реже чем методы. В действительности при наличии Func<> и Action<> кодопредставления там ненамного больше. Поэтому, лично я при связывании View к ViewModel о таких вещах не задумывался. Есть стандартный INotify — не хватает возможностей биндинга, реализую свой через свои события.
5. RoutedCommand все таки предназначен токмо для для донесения о события только в свою вьювмодель. Функциональная модель чаще совсем не совпадает с Visual, что ведет к дополнительным мыслительным процессам. Приглядись еще к CompositeCommand. Она лишена этого недостатка.
Re[4]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 08:17
Оценка:
Здравствуйте, MxMsk, Вы писали:

F>>А обработчик события ViewModel находится у тебя в code-behind View'юхи?

MM>Да. Я не нашел для себя плюсов в выносе обработчика за пределы View. Возможно, когда у нас будет по несколько View на одну модель, отделим. Но пока такого нет, а сама обработка событий зачастую связана с необходимостью манипулировать какими-нибудь контролами, заданными в XAML. Тут уж фиг чего в общий слой вынесешь.

У меня есть по крайней мере два случая, где вынос обработчика в Attached Property оказался просто необходим. Во-первых, это обработчики событий на окнах: Z-порядок, я уже писал и еще пара моментов. Т.к. окон разных много XXXWindow.xaml, то выбор либо наследовать один общий контрол от класса Window, либо модифицировать поведение AttachedBehavior'ами, накладывая нужное их множество на элемент окна. Иначе одна копипаста в code-behind. Делаю и так и так Во-вторых, я не знаю как делают другие отмену изменения выбранного элемента в ItemsControl'ах — банальная задача, когда пользователь выделяет в списке другой элемент, а надо его спросить: "Сохранить? Да/Нет/Отмена", но эту задачу я тоже реализовал при помощи интерфейса на ModelView и Attached Behavior'а на ItemsControl'е. Потому что ItemsControl может быть любым — ListBox, ListView и даже TabControl — вся логика в зависимости от того, на что его подсадили. заложена в Attached Behavior, и ничего не наследуется

MM>Вариантом отказа от событий в модели, может быть выставление через интерфейс нужных методов View. Можно сказать, что мы делаем обработчики частью контракта. Но это, конечно, неудобно, потому что требует держать в модели ссылку на представление.


Тоже пришло
Автор: Fortnum
Дата: 22.10.10
такое в голову, вот только если не на представление, а на некоторый его адаптер, который легко можно заменить на фэйковый при TDD. Адаптер создается на уровне View и кидается во ViewModel. А ViewModel дергает за методы этого адаптера, на самом деле даже не зная, что он представляет собой View или фэйк — кидать во ViewModel интерфейс адаптера. Хотя в итоге получится та же хрень, что у меня сейчас.

Нет. Я сейчас пришел к выводу, что нужно сделать некий универсальный интерфейс по типу INotifyPropertyChanged и INotifyCollectionChanged, через которые работает вся эта MVVM в части ModelView->View. Проблема заключается просто в том, что все равно потребуется нечто вроде адаптера, т.к. должно быть нечто вроде соглашения на стороне View'юхи: типа событие называется OnNavigateSignal, значит на стороне View'хи дергается метод Navigate. А это соглашение сейчас отсутствует, т.к. View'юхи все разные, а зачастую это и Windows Forms legacy-элементы Конечно, можно было бы сделать универсальное событие по типу Type.InvokeMethod, но чем это тогда отличается от бросания интерфейса адаптера View'юхи во ViewModel? Ничем. Значит автоматизировать можно лишь подписочно-отписочную часть, ну и может быть вызов каких-то простых методов View'юх, генерацию RoutedEvents и RoutedCommands на стороне View'юх, а в чуть более сложных случая придется дописывать адаптеры или в code-behind View'юхи.

Короче, попробую кое-что изобразить, залью сюда, оцените, что за хрень получится в итоге!
Re[2]: [WPF] События от ViewModel к View
От: Fortnum  
Дата: 22.10.10 08:45
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Конкретно по задаче: сделал бы свойства NavigationState и HttpHeaders во View и привязал бы к ним ViewModel. При изменении этих свойств View делал бы всю работу по изменению себя.

V>Никаких интерфейсов, ViewModel — это всегда конкретный класс, содержащий прикладную логику — это он сам обращается к всяким разным сервисам через интерфейсы.

Такое решение пришло мне в голову первым, очень-очень давно. Но я не стал его использовать и свалился к реализации интерфейсов во ViewModel'и. Объясню. Значит смотри, получается следующая система: если на View'хе надо вызвать какой-то метод или определенный алгоритм, во ViewModel'и выставляются параметры предстоящего вызова, а один из параметров триггерит этот вызов. В code-behind View'хи или в реализации Attached Property ты прописываешь реакцию на изменение свойства, которое триггерит вызов.

Плюсы: отсутствует система подписки-отписки.

Минусы: легко получается гипер-комплексная система (в моем случае легко), т.к. в попытке избавиться от event'ов во ViewModel'и ты фактически превращаешь ее в автомат конечных состояний. Текущее состояние этого автомата определяется множеством свойств ModelView'хи и их значений. Для простых случаев это работает, но если взять что-то посложнее... представь, что во View'хе сидит ActiveX Microsoft Word'а, и ModelView управляет его состоянием через свои Propert'исы, когда задача стоит стирать все и по команде генерить в этом Word'e какой-либо документ определенного вида, где алгоритм генерации однозначно находится на стороне ModelView т.к. в процессе генерации требуется очень много параметров... в общем, в какой-то момент времени у тебя этих Propert'исов на стороне ModelView будет безумное количество: наверняка пробовал рисовать диаграммы состояний в UML — относительно простые системы получаются легко и очень хорошо выглядят, но если чуть сложнее — приходится дополнять диаграммой последовательностей.

В данном случае, представь, что иногда надо посылать заголовки во время навигации, а иногда не надо. Следуя твоему варианту решения, необходимо во View добавить еще одно зависимое свойство UseHttpHeaders, и это только начало.

Кроме того, встает проблема окатов: например, когда ты свойство HttpHeaders во ViewModel'и поменял, а навигацию решил не делать — машина состояний будет находится в инвалидном состоянии. А где те заголовки, с которыми была открыта текущая страница? Вот.


Да и по сути, кроме отсутствия подписки-отписки твой вариант ничего не меняет — все равно приходится писать на стороне View'юх кучу кода

По сути, ты подписку-отписку отдаешь на откуп уже сделанной реализации подписки на INotifyPropertyChanged DataContext'ного объекта!

А концептуально поток событий ModelView-to-View в твоем варианте все равно имеется — то же PropertyChanged — то есть даже если исходить из пуристических побуждений отсутствия event'ов на стороне ViewModel, этот вариант тоже не проходит Так зачем за него цепляться, когда можно сделать себе много удобнее?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.