Как WPF-преобразователи могут использоваться в шаблоне MVVM?
Скажем, у меня есть представление, связанное с ViewModel A, которое имеет наблюдаемую коллекцию Клиенты.
Преимущество этого шаблона MVVM заключается в том, что я также могу привязать представление к ViewModel B, которое заполняет его разными данными.
Но что делать, если в моем конверторе Конвертер конверсий отображать моих клиентов, например. У меня есть "ContractToCustomerConverter", который принимает Контракт и возвращает соответствующего Клиента для отображения.
Проблема заключается в том, что преобразователь существует вне шаблона MVVM и, следовательно, не знает, что у моего ViewModel есть другой источник для клиентов.
- Есть ли способ, чтобы View передал ViewModel в конвертер, чтобы он участвовал в развязке, которую предоставляет шаблон MVVM?
- Есть ли способ для меня каким-то образом включить конвертер в мой ViewModel, чтобы конвертер использовал текущие зависимости, доступные ViewModel?
- или являются конверторами только прославленных кодовых и поэтому не используются в шаблоне MVVM, поэтому, если вы используете MVVM, тогда вы просто создаете свои собственные "конвертеры" (методы в вашем классе ViewModel), которые вернуть объекты, такие как объекты изображения, объекты видимости, FlowDocuments и т.д., которые будут использоваться в представлении, вместо использования конвертеров вообще?
(Я столкнулся с этими вопросами после просмотра использования конвертеров в демонстрационном приложении WPF, которое поставляется с загрузкой шаблона MVVM Template Toolkit, см. "Messenger Sample" после распаковки.)
Ответы
Ответ 1
Я вообще не использую конвертеры вообще в MVVM, за исключением чистых задач пользовательского интерфейса (например, BooleanToVisibilityConverter). ИМХО, вы должны скорее объявить свойство Customer типа CustomerViewModel в вашем проекте ContractViewModel, а не использовать ContractToCustomerConverter
Ответ 2
В этот разговор есть комментарий, который согласуется с положением Кента, а не использовать конвертеры вообще, интересно:
ViewModel - это в основном конвертер значений на стероидах. Требуется "сырые" данные и преобразует его во что-то приятное для восприятия, и наоборот. Если вы когда-либо обнаруживаете, что привязываете свойство element к ViewModel свойство, и вы используете конвертер значений, остановитесь! Почему бы просто не создать свойство в ViewModel, которое предоставляет "отформатированные" данные, а затем отбрасывает конвертер значений вообще?
И в этот разговор:
Единственное место, где я могу видеть использование преобразователи ценности в MVVM архитектура является кросс-элементом привязок. Если я связываю Видимость панели для IsChecked из CheckBox, тогда мне нужно будет использовать BooleanToVisibilityConverter.
Ответ 3
Преобразователи редко должны использоваться с MVVM. На самом деле я стараюсь не использовать их вообще. VM должна делать все, что нужно для выполнения своей задачи. Если для представления требуется Customer
на основе Contract
, на VM должно быть свойство Customer
, которое обновляется логикой VM, когда изменяется Contract
.
Преимущество этого шаблона MVVM заключается в том, что я также могу привязать View to ViewModel B, который заполняет его разными данными.
Я оспариваю это требование. По моему опыту, представления не разделяются между разными типами VM и не являются целью MVVM.
Ответ 4
Для тех, кто фактически не говорит "нетривиальных преобразователей" в представлении, как вы обрабатываете следующее?
Скажем, что у меня есть модель климатических датчиков, которая представляет временные ряды показаний с различных приборов (барометр, гигрометр, термометр и т.д.) в определенном месте.
Скажем, что моя модель просмотра предоставляет наблюдаемую коллекцию датчиков из моей модели.
У меня есть представление, содержащее набор инструментов WPF DataGrid
, который привязывается к модели просмотра с помощью свойства ItemsSource
, установленного на наблюдаемый набор датчиков. Как представить представление каждого инструмента для данного датчика? Отображая небольшой график (подумайте, пожалуйста, здесь Edward Tufte sparkline), который создается путем преобразования временных рядов в источник изображения с использованием конвертера (TimeSeriesToSparklineConverter
)
Вот как я думаю о MVVM: Модель предоставляет данные для просмотра моделей. Модель просмотра отображает поведение, данные модели и состояние для представления. Представления выполняют визуальную визуализацию данных модели и предоставляют интерфейс поведения, соответствующий состоянию View Model.
Таким образом, я не считаю, что изображения искровой линии идут в Модели (модель - это данные, а не их визуальное представление). Я также не верю, что изображения с искровой линзой входят в модель просмотра (что, если мой вид хочет представлять данные по-другому, скажем, как строка сетки, показывающая минимальное, максимальное, среднее, стандартное отклонение и т.д. Серии?). Таким образом, мне кажется, что представление должно обрабатывать работу по преобразованию данных в желаемое представление.
Поэтому, если я хочу разоблачить поведение, данные модели и заданное состояние для определенной модели просмотра в интерфейсе командной строки вместо графического интерфейса WPF, я не хочу, чтобы моя модель и моя модель просмотра содержали изображения. Это неправильно? У нас есть SensorCollectionGUIViewModel
и a SensorCollectionCommandLineViewModel
? Это кажется мне неправильным: я думаю о модели представления как абстрактном представлении представления, а не конкретном и привязаны к конкретной технологии, поскольку эти имена предполагают, что они есть.
То, что я в своем постоянно меняющемся понимании MVVM. Итак, для тех, кто говорит, что не использует конвертеры, что вы здесь делаете?
Ответ 5
Я добавлю свои 2 цента к этому обсуждению.
Я использую преобразователи, где это имеет смысл.
Объяснение:
Бывают случаи, когда вам нужно представить 1 значение в модели в других вариантах в пользовательском интерфейсе. Я выставляю это значение через 1 тип. Другой тип обрабатывается через конвертер. Если вы должны были разоблачить 1 значение через 2 свойства в VM, вам нужно будет вручную обрабатывать уведомления об обновлениях.
Например, у меня есть модель с 2 ints: TotalCount
, DoneCount
. Теперь я хочу, чтобы оба значения отображались в TextBlocks, и, кроме того, я хочу отобразить процент.
Я решаю это с помощью мультиконвертера DivisionConverter
, который принимает 2 ранее упомянутых ints.
Если у меня будет специальный PercentDone
в VM, мне нужно будет обновить это свойство всякий раз, когда обновляется DoneCount
.