Как можно использовать конвертеры WPF в шаблоне MVVM?

Допустим, у меня есть View, связанный с ViewModel A, который имеет наблюдаемую коллекцию Customers.

Преимущество этого шаблона MVVM состоит в том, что я также могу связать View с ViewModel B, которая заполняет его различными данными.

Но что, если в моих конвертерах View для отображения моих клиентов, например, у меня есть "ContractToCustomerConverter", который принимает контракт и возвращает соответствующего клиента для отображения.

Проблема в том, что конвертер существует вне шаблона MVVM и поэтому не знает, что у моей ViewModel есть другой источник для клиентов.

  • Есть ли способ для View, чтобы передать ViewModel в Converter, чтобы он участвовал в развязке, которую обеспечивает шаблон MVVM?
  • Есть ли способ для меня как-то включить конвертер в моей ViewModel так, чтобы конвертер использовал текущие зависимости, которые ViewModel имеет в наличии?
  • или конвертеры просто прославляют выделенный код и поэтому не используются в шаблоне MVVM, поэтому, если вы используете MVVM, вы просто создаете свои собственные "конвертеры" (методы в своем классе ViewModel), которые возвращают такие вещи, как объекты Image, объекты Visibility, FlowDocuments и т. д. для использования в представлении, вместо использования преобразователей вообще?

(Я столкнулся с этими вопросами после того, как увидел использование конвертеров в демонстрационном приложении WPF, которое поставляется вместе с загрузкой MVVM Template Toolkit, см. "Образец Messenger" после распаковки.)

5 ответов

Я обычно вообще не использую конвертеры в MVVM, за исключением задач с чистым пользовательским интерфейсом (например, BooleanToVisibilityConverter). ИМХО, вам лучше объявить свойство Customer типа CustomerViewModel в ContractViewModel, а не использовать ContractToCustomerConverter

В этом разговоре есть комментарий, который согласен с позицией Кента, не использовать конвертеры вообще, интересно:

ViewModel в основном конвертер значений на стероидах. Он берет "сырые" данные и преобразует их во что-то удобное для представления, и наоборот. Если вы когда-нибудь обнаружите, что привязываете свойство элемента к свойству ViewModel и используете конвертер значений, остановитесь! Почему бы просто не создать свойство в ViewModel, которое предоставляет "отформатированные" данные, а затем вообще удалить преобразователь значений?

И в этом разговоре:

Единственное место, где я могу увидеть использование преобразователей значений в архитектуре MVVM - это привязки между элементами. Если я связываю Видимость панели с проверкой IsChecked CheckBox, тогда мне нужно будет использовать BooleanToVisibilityConverter.

Конвертеры должны редко использоваться с MVVM. На самом деле, я стараюсь не использовать их вообще. ВМ должна делать все, что нужно представлению, чтобы выполнить свою работу. Если представление нуждается в Customer основанный на Contractдолжно быть Customer свойство на виртуальной машине, которое обновляется логикой виртуальной машины всякий раз, когда Contract изменения.

Преимущество этого шаблона MVVM состоит в том, что я также могу связать View с ViewModel B, которая заполняет его различными данными.

Я оспариваю это утверждение. По моему опыту, представления не разделяются между различными типами виртуальных машин, и это не является целью MVVM.

Для тех, кто фактически говорит "нетривиальные конвертеры" в представлении, как вы справляетесь со следующим?

Допустим, у меня есть модель климатических датчиков, которая представляет временные ряды показаний различных приборов (барометр, гигрометр, термометр и т. Д.) В данном месте.

Предположим, что моя модель представления предоставляет видимую коллекцию датчиков из моей модели.

У меня есть представление, содержащее инструментарий WPF DataGrid который связывается с моделью представления с ItemsSource свойство установлено на наблюдаемую коллекцию датчиков. Как мне представить вид каждого инструмента для данного датчика? При отображении небольшого графика (например, спарклайн Эдварда Туфте), который генерируется путем преобразования временного ряда в источник изображения с использованием преобразователя (TimeSeriesToSparklineConverter)

Вот как я думаю о MVVM: Модель предоставляет данные для просмотра моделей. Модель представления отображает поведение, данные модели и состояние для просмотра. Представления выполняют визуальное представление данных модели и предоставляют интерфейс для поведения, согласующегося с состоянием модели представления.

Таким образом, я не верю, что спарклайн-изображения идут в модели (модель - это данные, а не конкретное их визуальное представление). Также я не верю, что спарклайн-изображения идут в модели представления (что, если мой вид хочет представить данные по-другому, скажем, в виде строки сетки, просто показывающей минимальное, максимальное, среднее, стандартное отклонение и т. Д. Серии?). Таким образом, мне кажется, что представление должно обрабатывать работу по преобразованию данных в желаемое представление.

Поэтому, если я хочу представить поведение, данные модели и заданное состояние для определенной модели представления в интерфейсе командной строки вместо графического интерфейса WPF, я не хочу, чтобы моя модель или модель представления содержали изображения. Это неправильно? Должны ли мы иметь SensorCollectionGUIViewModel и SensorCollectionCommandLineViewModel? Мне это кажется неправильным: я считаю модель представления абстрактным представлением, а не конкретным и привязанным к конкретной технологии, как предполагают эти названия.

Вот где я нахожусь в моем постоянно развивающемся понимании MVVM. Так что для тех, кто говорит не использовать конвертеры, что вы здесь делаете?

Я использую Stackru в течение многих лет, и это мой первый опубликованный ответ.

Я думаю, что конвертеры относятся к View в MVVM, рассмотрим следующую ситуацию:

Приложение разрабатывают 3 команды: команда webapi, команда веб-клиентов и команда UI. Пользовательский интерфейс часто менялся, поэтому команда веб-клиентов (которая получает данные из веб-интерфейса и помещает их в модель просмотра) не всегда может изменить модель просмотра для удовлетворения потребностей пользовательского интерфейса. Это становится невозможным, когда у команды UI есть разные версии дизайна. Таким образом, команда пользовательского интерфейса должна иметь собственный способ представления данных, и решение - преобразователи.

Надеюсь, это кому-то поможет.

Я добавлю свои 2 цента к этой дискуссии.

Я использую конвертеры, где это имеет смысл.

Объяснение: Существуют случаи, когда вам нужно представить 1 значение в модели несколькими способами в пользовательском интерфейсе. Я выставляю это значение через 1 тип. Другой тип обрабатывается через конвертер. Если бы вы выставили 1 значение через 2 свойства в ВМ, вам бы пришлось вручную обрабатывать уведомления об обновлениях.

Например, у меня есть модель с 2 дюймами: TotalCount, DoneCount, Теперь я хочу, чтобы оба этих значения отображались в TextBlocks, и, кроме того, я хочу, чтобы отображался процент выполнения.

Я решаю это с помощью DivisionConverter мульти конвертер, который занимает 2 ранее упомянутых целых

Если бы у меня был особенный PercentDone в ВМ мне нужно будет обновить это свойство всякий раз, когда DoneCount обновляется.

Другие вопросы по тегам